一、代理不生效
1、@Transactional注解最好不要标注在接口方法上。最好直接标注在实现类或实现方法上。
spring2.0之后如果不在配置文件中指定,默认生成代理的方式为CGLIB,如果@Transactional标注在接口上,而接口的实现类的代理方式如果是CGLIB,将无法解析到@Transactional,事务失效。
2、被final、static关键字修饰的类或方法。
CGLIB是通过生成目标类子类的方式生成代理类的,被final、static修饰后,无法继承父类与父类的方法了。
3、类方法内部调用
事务的管理是通过代理执行的方式生效的,如果是方法内部调用,将不会走逻辑,也就调用不到。
4、当前类没有被Spring管理
二、框架或底层不支持
1、不支持非public修饰的方法进行事务管理。
2、多线程调用
3、数据库本身不支持事务
例如MySQL的Myisam存储引擎不支持事务,只有innodb存储引擎才支持,但mysql5之后默认使用innodb
4、未开启事务
该问题springboot中不存在,springboot默认开启了事务管理。
三、错误使用@Transactional
1、错误的传播机制
2、rollbackFor属性设置错误
默认情况下事务仅回滚运行时异常和Erroe,不回滚编译时异常,所以如果方法中抛出IO异常,默认情况下也会回滚失败。
3、异常被内部catch
但是在UserSevice中我们捕获了异常,此时UserService上的事务认为正常提交事务。最后在提交时发现事务只读,已经被回滚,则抛出了上述异常。
因此这里如果需要对特定的异常进行捕获处理,记得再次将异常抛出,让最外层的事务感知到。
4、嵌套事务
如果出现同时回滚两个service中的方法,则不需要处理。但是如果出现一个方法中只回滚一个service中报错的数据库操作,有两种方式解决。
1)直接在service 中的整个方法用try catch包住
2)在在service中使用Propagation.REQUIRES_NEW传播机制
总结: