上面我们讨论了NEVER和MANDATORY的作用,下面我们接着讨论其他情况。
3. SUPPORTS
如果有事务则加入该事务,如果没有存在的事务则以非事务的方式运行。
我们先让insertSubTable方法在无事务的情况下运行。配置文件为:
<tx:attributes> <!-- <tx:method name="insertSuperTable" propagation="REQUIRED"/> --> <tx:method name="insertSubTable" propagation="SUPPORTS"/> </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========"); } }
运行测试方法:
从上面可以看出,如果没有父事务,SUPPORTS标注的方法完全是非事务运行的。下面我们给它一个父事务,先修改配置文件:
<tx:attributes> <tx:method name="insertSuperTable" propagation="REQUIRED"/> <tx:method name="insertSubTable" propagation="SUPPORTS"/> </tx:attributes>
然后运行测试方法:
从上面可以看出子方法加入了父方法的事务,所以父方法对数据库的修改是对子方法可见的。
我们来看看发生异常时的回滚,这里只讨论有事务存在的情况,因为如果没有事务,它就以非事务方式运行,也就不存在回滚。
①RuntimeException
跟MANDATORY一样,SUPPORTS标注的方法是直接加入父事务,成为父事务的一部分,他们共享一个connect。所以当子事务抛出RuntimeException回滚的时候,父事务也不得不一起回滚。
②Throwable和Exception
跟MANDATORY一样,如果不配置rollback-for属性,抛出Throwable和Exception都不会导致父子事务回滚,而是在哪儿出异常就在哪儿提交,就有可能出现部分提交的现象。
我们可以用rollback-for属性来让抛Throwable和Exception时也回滚。由于SUPPORTS标注的方法是直接加入父事务,所以子类发生Throwable或Exception,就会父子一起回滚。
4. NOT_SUPPORTED
当前方法不运行在任何事务之中,如果有已经存在的事务则将该事务挂起,直到当前方法以非事务的方式执行完毕,挂起的事务才会继续执行。我们修改下配置文件:
<tx:attributes> <tx:method name="insertSuperTable" propagation="REQUIRED"/> <tx:method name="insertSubTable" propagation="NOT_SUPPORTED"/> </tx:attributes>
然后执行测试方法:
从上面可以看出子方法以非事务方法执行,而父方法以事务方式执行,父方法对数据库的修改是否对子方法可见,取决于数据库的事务隔离级别。如果隔离级别是Read Uncommitted,则可见。
我再来看看异常回滚:
①RuntimeException
我们先让insertSubTable方法抛出一个RuntimeException:
子事务类:
@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); ExceptionUtils.throwRuntimeException(); //这里抛出RuntimeException jt.execute(insertSubTable2); System.out.println("========insertSubTable end========"); } }
执行测试类:
从上面可以看出,这里抛RuntimeException回滚的效果有点不一样,并不是所以操作都回滚。因为insertSuperTable方法由于在事务中,所以所有插入都回滚了。但insertSubTable不属于任何事务,所以第一个插入成功了,后来就抛异常退出了。
②Throwable和Exception
如果在无事务的insertSubTable中抛出异常,则在哪儿出异常就在哪儿提交。rollback-for属性对NOT_SUPPORTED无效,因为它本身就不在事务中,也不会回滚。
本文出自 “銅鑼衛門” 博客,请务必保留此出处http://jaeger.blog.51cto.com/11064196/1761851
原文:http://jaeger.blog.51cto.com/11064196/1761851