1 访问权限问题:
java的访问权限有4种:private、default、protected、public,它们的权限从左到右,以此变大。如果在开发中,将事务方法定义了错误的访问权限,则事务功能会失效。这样会导致事务失效,spring要求被代理方法必须是public的。、
在Spring源码中,如果目标方法不是public,则TransactionAttribute返回null,不支持事务。
2 方法用final修饰
放方法被final修饰时,也会导致事务失效。
因为spring事务底层是用了aop,用了jdk的动态代理或者cglb的动态代理,会帮我们生成代理类,在代理类中实现事务功能。
如果某个方法被final修饰了,那么在代理类中,就无法重新该方法,而添加事务功能。
注意:如果某个方法被static修饰,同样也无法通过动态代理,变成事务方法。
3 直接调用内部方法
由上可知:在事务方法add可知,它直接调用了updateStatus方法,
由2可知:方法拥有事务的能力是因为spring aop中生成了代理对象,但是直接调用updateStatus方法不会直接生成事务。
但是可以直接将该类直接注入进来,比如:
这样事务就生效了,也不会穿生循环依赖的问题。
4 未被Spring管理
5 多线程调用
由以下代码可知:在add()事务方法里面,调用了updateStatus事务方法,但是updateStatus事务方法是在另外一个线程中调用的。这样就导致了两个方法不在同一个线程中,获取到了数据库连接不一样,从而是两个不同的事务,如果updateStatus方法中抛出了异常,add方法是不会回滚的
spring的事务是通过数据库的连接来实现的。当前线程中保存了一个map,key是数据源,value是数据库连接。同一个事务,指同一个数据库连接,只有拥有同一个事务连接才能保证同时提交和回滚。如果是不同的线程,拿到的数据库连接肯定是不同的。
6 表不支持事务
如果表的引擎是myisam,那么它是不支持事务的,要想支持事务,改成innodb引擎
7 事务没有开启
如果是springBoot项目,那么是事务默认是开启的,但如果是spring项目,需要xml配置
8 事务的传播特性
如果事务的传播特性设置错了,事务也会失效。如下:propagation = Propagation.NEVER这种类型的传播特性不支持事务,如果有事务会抛出异常。
目前只有这三种传播特性才会创建新事物:REQUIRED、REQUIRES_NEW、NESTED
9 自己吞了异常
事务不会回滚,最常见的问题是:开发者在代码中手动try...catch了异常。如下:
这种情况下,因为开发者自己捕获了异常、又没有手动抛出
10 手动抛了别的异常
如果抛的异常不正确,事务也不会回滚
因为Spring事务,默认情况下只会回滚RuntimeException(运行时异常)和Error(错误),对于普通的非运行时异常,它不会回滚。
11 自定义回滚异常
如果在使用@Transactional注解声明事务时,有时想自定义回滚异常,spring也是支持的。可以通过设置rollbackFor参数,来完成这个功能。如下:
但是如果在程序执行过程中,出现了sql异常,但是sql异常并不属于我们定义的BusinessException异常,所以事务也不会回滚