Isolation :隔离级别java
隔离级别是指若干个并发的事务之间的隔离程度,与咱们开发时候主要相关的场景包括:脏读取、重复读、幻读。mysql
具体的设置方式(注解):例如@Transactional(isolation = Isolation.DEFAULT )spring
隔离级别 | 含义 |
---|---|
DEFAULT | 使用数据库默认的事务隔离级别 |
READ_UNCOMMITTED | 容许读取还没有提交的修改,可能致使脏读、幻读和不可重复读 |
READ_COMMITTED | 容许从已经提交的事务读取,可防止脏读、但幻读,不可重复读仍然有可能发生 |
REPEATABLE_READ | 对相同字段的屡次读取的结果是一致的,除非数据被当前事务自生修改。可防止脏读和不可重复读,但幻读仍有可能发生 |
SERIALIZABLE | 彻底服从acid隔离原则,确保不发生脏读、不可重复读、和幻读,但执行效率最低。 |
Propagation:传播行为sql
所谓事务的传播行为是指,若是在开始当前事务以前,一个事务上下文已经存在,此时有若干选项能够指定一个事务性方法的执行行为。数据库
具体的设置方式(注解):@Transactional(propagation = Propagation.REQUIRED)express
传播行为 | 含义 |
---|---|
REQUIRED | 表示当前方法必须在一个具备事务的上下文中运行,若有客户端有事务在进行,那么被调用端将在该事务中运行,不然的话从新开启一个事务。(若是被调用端发生异常,那么调用端和被调用端事务都将回滚) |
MANDATORY | 表示当前方法必须在一个事务中运行,若是没有事务,将抛出异常 |
NEVER | 表示当方法务不该该在一个事务中运行,若是存在一个事务,则抛出异常 |
NOT_SUPPORTED | 表示该方法不该该在一个事务中运行。若是有一个事务正在运行,他将在运行期被挂起,直到这个事务提交或者回滚才恢复执行 |
SUPPORTS | 表示当前方法没必要须要具备一个事务上下文,可是若是有一个事务的话,它也能够在这个事务中运行 |
NESTED | 表示若是当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中,被嵌套的事务能够独立于被封装的事务中进行提交或者回滚。若是封装事务存在,而且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。若是封装事务不存在,则同propagation_required的同样 |
REQUIRES_NEW | 表示当前方法必须运行在它本身的事务中。一个新的事务将启动,并且若是有一个现有的事务在运行的话,则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行。 |
几点说明:编程
导入外部资源文件后端
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder
注册组件包扫描,把类上标注了@Controller @Service @Repository @Component 都会自动加入到Spring容器中springboot
<context:component-scan base-package="zfcoding.tx.aspectaop"></context:component-scan>
<<tx:advice>>配置一个事物通知,即执行的方法隔离级别和传播行为, <<aop:config>>配置事务通知在类上执行操做(切入点)。并发
<tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- 为链接点指定事务属性 --> <tx:method name="insert*" isolation="DEFAULT" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="point" expression="execution (* zfcoding.tx.aspectaop..*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="point"></aop:advisor> </aop:config>
实现步骤:
一、定义数据库的配置文件(db.properties),定义业务类UserDao,UserService。
二、定义Spring的配置文件(spring-aspect.xml)
导入经过<<context:property-placeholder>>导入数据库配置文件,而后经过包扫描的方式<<context:component-scan>>把UserDao,UserService注册到Spring的容器当中,配置数据额源,JDBC 的模板,最后事务管理器,配置事务通知,切入点。
配置文件(db.properties)
db.username=root db.password=root db.url=jdbc:mysql://127.0.0.1:3306/springboot?serverTimezone=UTC&useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8 db.driverClass=com.mysql.jdbc.Driver
业务类(UserDao,UserService)
@Repository public class UserDao { @Autowired private JdbcTemplate jdbcTemplate; public void insertUser() { String sql = "INSERT INTO t_user (username,`password`) VALUES(?,?);"; String username = UUID.randomUUID().toString().substring(0, 3); jdbcTemplate.update(sql, username, 12); System.out.println("插入成功"); int i=10/0; } } @Service public class UserService { @Autowired private UserDao userDao; public void insertUser() { userDao.insertUser(); } }
Spring配置文件(spring-aspect.xml)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 导入外部资源文件 --> <context:property-placeholder location="classpath:db.properties"></context:property-placeholder> <!--包扫描,把类上标注了@Controller @Service @Repository @Component 都会自动加入到Spring容器中--> <context:component-scan base-package="zfcoding.tx.aspectaop"></context:component-scan> <!-- 配置C3P0数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${db.username}"></property> <property name="password" value="${db.password}"></property> <property name="jdbcUrl" value="${db.url}"></property> <property name="driverClass" value="${db.driverClass}"></property> </bean> <!-- 配置Spring 的JdbcTemplate --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- 为链接点指定事务属性 --> <tx:method name="insert*" isolation="DEFAULT" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="point" expression="execution (* zfcoding.tx.aspectaop..*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="point"></aop:advisor> </aop:config> </beans>
测试方法
public class AspectTest { @Test public void aspectAop(){ ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:spring-aspect.xml"); UserService userService = applicationContext.getBean(UserService.class); userService.insertUser(); } }
基于注解实现
第一步是在须要事务的类或者方法上面添加@Transactional()
注解,里面能够经过propagation和isolation指定事务的隔离级别和传播行为。
@Service public class UserService { @Autowired private UserDao userDao; @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT) public void insertUser() { userDao.insertUser(); } }
@EnableTransactionManagement
来启用注解式事务管理,至关于以前在xml中配置的<tx:annotation-driven />
注解驱动。
经过包扫描@ComponentScan至关于 <<context:component-scan>>实现业务类注册到Spring容器当中。
经过@PropertySource和 @Value实现读取配置文件,而且把之赋值到对应的属性当中。
@Configuration 说明该类是一个配置类至关于(<beans></beans>),@Bean 至关于(<bean></bean>),注册数据源,JDBC模板,事务管理器。
@EnableTransactionManagement @ComponentScan(basePackages = "zfcoding.tx") @PropertySource("classpath:db.properties") @Configuration public class MyDataSourceConfig { @Value("${db.username}") private String username; @Value("${db.password}") private String password; @Value("${db.url}") private String url; @Value("${db.driverClass}") private String driveClass; @Bean public DataSource dataSource() throws PropertyVetoException { ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setUser(username); dataSource.setPassword(password); dataSource.setJdbcUrl(url); dataSource.setDriverClass(driveClass); return dataSource; } @Bean public JdbcTemplate jdbcTemplate() throws PropertyVetoException { JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(dataSource()); return jdbcTemplate; } //注册事务管理器在容器中 @Bean public PlatformTransactionManager transactionManager() throws PropertyVetoException { return new DataSourceTransactionManager(dataSource()); } }
测试类
public class TxTest { @Test public void test(){ AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MyDataSourceConfig.class); UserService userService = applicationContext.getBean(UserService.class); userService.insertUser(); } }
基于xml实现
配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 导入外部资源文件 --> <context:property-placeholder location="classpath:db.properties"></context:property-placeholder> <!--包扫描,把类上标注了@Controller @Service @Repository @Component 都会自动加入到Spring容器中--> <context:component-scan base-package="zfcoding.xmltx"></context:component-scan> <!-- 配置C3P0数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${db.username}"></property> <property name="password" value="${db.password}"></property> <property name="jdbcUrl" value="${db.url}"></property> <property name="driverClass" value="${db.driverClass}"></property> </bean> <!-- 配置Spring 的JdbcTemplate --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--开启自动事务扫描--> <!-- 启用事务注解 --> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
测试类
public class XmlTxTest { @Test public void test(){ ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:bean.xml"); UserServiceXml userServiceXml = applicationContext.getBean(UserServiceXml.class); userServiceXml.insertUser(); } }
以上就是Spring 事务配置的全过程,完事。
往期内容
我是阿福,公众号「阿福聊编程」做者,对后端技术保持学习爱好者,我会常常更新JAVA技术文章,在进阶的路上,共勉!
欢迎你们关注个人公众号,后台回复666,领取Java全套进阶实战课程。