spring 事务控制(传播级别详解以及示例)
1.spring 对事务控制的两种方式
A.声明式事务配置,在xml中配置事务的数据源,隔离界别,传播策略,切点,切面
B.通过spring注解的方式
spring xml 配置 <!--配置 spring data access 管理器-->
<bean id="jdbcTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource"> <ref bean="dataSource"/> </property> </bean> <!--配置事物传播策略,以及隔离级别--> <tx:advice id="txAdvice" transaction-manager="jdbcTransactionManager"> <tx:attributes> <!-- 注入事务策略 --> <tx:method name="delet*" propagation="REQUIRED" isolation="READ_COMMITTED" rollback-for="Exception"/> <tx:method name="updat*" propagation="REQUIRED" isolation="READ_COMMITTED" rollback-for="Exception"/> <tx:method name="delet*" propagation="REQUIRED" isolation="READ_COMMITTED" rollback-for="Exception"/> <tx:method name="inser*" propagation="REQUIRED" isolation="READ_COMMITTED" rollback-for="Exception"/> <!-- <tx:method name="*" propagation="REQUIRED" isolation="READ_COMMITTED"/> --> </tx:attributes> </tx:advice> <!-- AOP切面和通知编织在一起 --> <aop:config>
<aop:pointcut id="service" expression="(execution(public * *..*.service.impl.*.*(..)))"/> <!-- 注入切点,切点策略 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="service" order="1"/> </aop:config>
spring 注解方式
@Transactional(propagation = Propagation.NEVER,rollbackFor = Exception.class,isolation=Isolation.READ_COMMITTED)
propagation:事务的传播策略
roobackFor: 事务的回滚策略
isolation:事务的隔离级别
2.事务隔离级别
spring 的事务隔离级别有七种
REQUIRED:要求有事务,没有事务就加一个事务。
eg:外层方法A没有事务,内层方法B声明了事务,B方法先执行,A方法内异常后发生,数据依然能变更。B事务不受A的影响
外层方法A有事务,内层方法B有事务,B将和A公用一个事务,A 或B 任何一个有异常都将回滚。
REQUIRES_NEW:不管外层有没有事务都新加一个事务 (注意:没用通过spring 管理的方法,REQUIRES_NEW 不会生效)
eg:通过this对象调用的带有事务的方法,解决办法:1.调用其他service中被托管的方法,2.获取spring上下文,获取bean工厂中的实例,调用对应的方法
外层A有事务,内层B声明了新的事务,B异常,A回滚,A异常B不会回滚
类TransationServiceImpl @Autowired private TransationTestService testService; @Override @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class,isolation = Isolation.READ_COMMITTED) public void requiresNew() { // this.haveTra(); //重点:通过this实例调用的方法,并不会被spring的AOP进行托管,所有不论何时都会回滚 testService.haveTra(); dao.insertInfo(); int i=1/0; } 类TransationTestServiceImpl @Override @Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class,isolation = Isolation.READ_COMMITTED) public void haveTra(){ dao.insertInfo(); }
NESTED:嵌套事务,内存事务是外层事务的一部分,内层事务执行完毕不会立即提交,会和外层事务一起提交
eg:外层方法A声明了一个嵌套事务,内层方法B声明一个事务,B的事务是A的子事务,B事务会保存一个回滚点savepoint,当B执行完还不会提交,只有到A执行完才会提交,所以不论A或者B任何
方法有异常,都会回滚。
NESTED和REQUIRES_NEW 区别在于提交的时机不同,NESTED 内层方法等待外层事务一起提交,REQUIRES_NEW 不管外层直接提交
类TransationServiceImpl @Autowired private TransationTestService testService; @Override @Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class,isolation = Isolation.READ_COMMITTED) public void requiresNew() { testService.haveTra(); try { //在此之前刷新数据库事务还未提交 Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } dao.insertInfo("2"); //外层执行完毕,两个事务一起提交 //int i = 1 / 0; } 类TransationTestServiceImpl @Override @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class,isolation = Isolation.READ_COMMITTED) public void haveTra(){ dao.insertInfo("1"); }
NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
eg:外层方法A声明REQUIRE,内层方法B声明NEVER,抛出异常
SUPPORTS:当前有事务就以事务执行,没有就以非事务执行
MANDATORY:支持当前的事务,没有事务抛出异常
NOT_SUPPORTED:以非事务的方式运行。