背景
-
@Transactional放在类上面和放在方法上面的优先级。注解放在方法上面会覆盖放在类上面。
-
@Transactional注解的属性的含义:事务传播?事务隔离级别?是否只读?
-
失效的场景有哪些?
a) 内部方法调用
b) try…catch
c) 默认是RuntimeException级别的,那么Exception级别的异常框架就感知不到
过程
-
内部方法调用
场景描述:一个方法没有事务,但是调用了一个有事务的方法,此事务失效。
测试代码
- 设计两个方法。methodA(), methodB()
- methodA是没有事务注解的。
- methodB是有事务注解的。
- 测试methodA去调用methodB。
- 此时methodB方法中,先执行更新数据库,然后出现异常,未捕获。
测试结果
事务失效。数据被更新到数据库中。
虽然代码报错了,但是数据库的更新操作,依然发生了。
本意是要保证事务,当代码抛出异常了,那么事务就回滚了。但是,由于方法间的调用关系,导致了事务失效。
-
try…catch
方法中出现了异常,且未捕获。Spring的默认异常感知级别是RuntimeException,因此如果是Exception级别的异常,Spring是无法感知的。此时如果数据已经更新到数据库了,发生了Exception级别的异常,则不会回滚。事务失效。
如果出现了异常,但是捕获了。数据库中的数据最终会被更新。事务失效。
-
默认是RuntimeException级别的,那么Exception级别的异常框架就感知不到
- 在测试try catch的时候,如果捕获了异常,则数据最终被更新到数据库中。事务失效,因为捕获了异常,并处理了异常。
- 如果没有捕获异常,则框架感知到异常发生的级别是RuntimeException,如果代码抛出了Exception级别的异常,则事务依然失效。
小结
-
遇到异常检测不回滚
原因:默认RuntimeException级别才回滚。如果是Exception级别的异常需要手动添加@Transactional(rollbackFor=Exeception.class)。
-
主动捕获异常导致框架无法捕获,从而导致事务失效。
-
一个合理实践是这样的。
a, 业务service层,直接抛出异常,让Controller层捕获异常并处理。
b,这样实践后,当service层发生了异常情况。而业务层的异常被框架感知到了,因此事务是有效的。这里的框架就是Spring的事务。
c, 注意:非常重要。一定要注意级别:rollbackFor=Exeception.class