事务传播行为
7种传播行为


REQUIRED(默认)
REQUIRED(默认)
propagation写在子方法上,对子方法生效(所有传播方式都是这样)
propagation写在子方法上,对子方法生效(所有传播方式都是这样)
REQUIRED_NEW
REQUIRED_NEW如下图,对purchase注释REQUIRED_NEW,第一个purchase执行成功后,第二个purchase如果执行失败,不会回滚第一个。
但是第二个purchase抛出了异常,checkout里没有对其捕获,或导致checkout回滚,就是说如果purchase前有直接操作数据库的非事务,会被回滚(由于checkout是事务,拦截到了purchase抛出来的异常)。

死锁:使用REQUIRED_NEW要特别注意死锁!
REQUIRED_NEW要特别注意死锁!以下代码为例,transaction接口transactionNewHelloWorld做了如下事情
1.调用helloDao.updateNameById对hello表进行了修改;
2.调用helloWorldService.updateHelloWorld对hello表和world表进行了修改。
外部只要调用transactionNewHelloWorld 这个方法就会发生死锁,因为外部事务先对hello表加锁了,内部事务REQUIRES_NEW会新开一个事务,想要获得hello的锁,但是获得不到,产生死锁。
如果将上面两步换一下就不会发生死锁了。
If you really need to do it in separate transaction you need to use
REQUIRES_NEWand live with the performance overhead. Watch out for dead locks.I'd rather do it the other way:
Validate data on Java side.
Run everyting in one transaction.
If anything goes wrong on DB side -> it's a major error of DB or validation design. Rollback everything and throw critical top level error.
Write good unit tests.
REQUIRED_NEW和REQUIRED异常回滚
REQUIRED_NEW和REQUIRED异常回滚GitHub Code: feat: 对REQUIRED和REQUIRES_NEW异常捕获测试
假设只有BBB的e3处会抛出异常,且一定会抛出异常
e1:在
MAIN里(e1处)捕获异常,一定能捕获得到,且不会再抛出异常。这里是否捕获异常不会影响update的结果e3:在此处捕获异常相当于没有抛出异常,
update函数正常运行。e2:只在此处捕获异常
p1(即
helloworld的传播属性是REQUIRED):会执行catch里句子,但仍然会抛出以下异常,最终结果是全部没有执行(update的1和helloworld的1都被回滚了)。UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
I cannot catch exceptions in method annotated @Transactional
Spring docs:Transaction Management
p2:
update的1执行完成(不回滚),helloworld的1和3都没有执行(1被回滚,没有执行到3这里来)。
e123都没捕获:(两种结果是一样的,和e2 p1相比,只有抛的异常不一样)。
p1:最终结果是全部没有执行(
update的1和helloworld的1都被回滚了)p2:最终结果是全部没有执行(
helloworld的1被回滚,没有执行到3这里来;update的1由于helloworld抛出的异常而被回滚)。
默认RuntimeException 和 Error 导致回滚
RuntimeException 和 Error 导致回滚没试过:即使没写RuntimeException,也会包括其中
No need to include
RuntimeExceptioninrollbackForlist. It will handle that even if you do not mention it.I've tried it out for jdbcTemplate:-
noRollbackFor的问题没搞懂
在一个非transaction方法里调同类的另一个transaction方法,transaction不生效;
法1.需要@Resource注入+context.getBean调用
法2.如果不用@Resource注入的话,则继承ApplicationContextAware
Last updated
Was this helpful?