最后这篇文章我们来讨论开发中最常用的剩下三种事务传播机制:REQUIRED、REQUIRES_NEW和NESTED
5. REQUIRED
REQUIRED是我们最常用的传播机制。如果当前有存在的事务则加入该事务,如果没有则新开一个事务。
先修改配置文件:
<tx:attributes> <tx:method name="insertSuperTable" propagation="REQUIRED"/> <tx:method name="insertSubTable" propagation="REQUIRED"/> </tx:attributes>
父事务类:
@Component public class TransactionSuper { @Autowired TransactionSub transactionSub; String insertSuperTable1 = "insert into super_table values (1, ‘super1‘)"; String insertSuperTable2 = "insert into super_table values (2, ‘super2‘)"; public void insertSuperTable(AbstractApplicationContext ctx) throws Exception{ System.out.println("========insertSuperTable start========"); JdbcTemplate jt = (JdbcTemplate)ctx.getBean("jdbcTemplate"); jt.execute(insertSuperTable1); transactionSub.insertSubTable(ctx); jt.execute(insertSuperTable2); System.out.println("========insertSuperTable end========"); } }
子事务类:
@Component public class TransactionSub { String insertSubTable1 = "insert into sub_table values (1, ‘sub1‘)"; String insertSubTable2 = "insert into sub_table values (2, ‘sub2‘)"; public void insertSubTable(AbstractApplicationContext ctx) throws Exception { System.out.println("========insertSubTable start========"); JdbcTemplate jt = (JdbcTemplate) ctx.getBean("jdbcTemplate"); jt.execute(insertSubTable1); jt.execute(insertSubTable2); System.out.println("========insertSubTable end========"); } }
然后运行测试方法
如果有存在的事务,跟MANDATORY效果一样,也是加入该事务,并且共用一个connection,所以父子方法对数据库的修改都是相互可见的。没有事务的情况这里就不再演示了,也就是insertSubTable方法自己新开一个事务。
我们来看看发生异常时的回滚,其实基本跟MANDATORY一样,只是子方法可以自己开启事务,而不一定要加入其它事务之中。
①RuntimeException
如果有已经存在的事务,跟MANDATORY一样,REQUIRED标注的方法是直接加入父事务,成为父事务的一部分,他们共享一个connection。所以不管是子事务还是父事务抛出RuntimeException的时候,父子事务都会回滚。如果没有事务,就只回滚子方法新开事务中的操作。
②Throwable和Exception
跟MANDATORY一样,如果不配置rollback-for属性,抛出Throwable和Exception都不会导致父子事务回滚,而是在哪儿出异常就在哪儿提交,就有可能出现部分提交的现象。
我们可以用rollback-for属性来让抛Throwable和Exception时也回滚。由于REQUIRED标注的方法是直接加入父事务,所以子类发生Throwable或Exception,就会父子一起回滚。
6. REQUIRES_NEW
被REQUIRES_NEW标记的方法会新建事务,如果当前存在事务,把当前事务挂起,等待新开事务完成后,被挂起的事务再恢复执行。
先修改配置文件:
<tx:attributes> <tx:method name="insertSuperTable" propagation="REQUIRED"/> <tx:method name="insertSubTable" propagation="REQUIRES_NEW"/> </tx:attributes>
直接执行测试方法:
从上面可以很明显的看出insertSubTable方法新开了一个connection并重启了一个新事务,insertSuperTable和insertSubTable是两个不同的connection中的两个不同的事务。所以父方法对数据库的修改是否对子方法可见,取决于数据库的事务隔离级别。
REQUIRES_NEW由于开了新连接和新事务,所以异常回滚跟其他事务传播机制有很大区别,下面我们结合具体实例来说明。
①RuntimeException