1.事务方法访问修饰符非public
@Transactional
private void method{
// 业务逻辑处理......
// 事务不生效......
}
@Transactional
protected void method{
// 业务逻辑处理......
// 事务不生效......
}
2.修饰符static、final修饰的,同样无法通过动态代理,事务也是不会生效
Spring的声明式事务是基于动态代理实现的,我们无法重写final修饰的方法;
不管是JDK动态代理还是Cglib的动态代理,就是要通过代理的方式获取到代理的具体对象,而static方法修饰的方法是属于类的,不属于任何对象,所以static方法不能被重写,即便写法上是重写,但是并不具备重写的含义,也就是说static方法也不被进行动态代理。
3.@Transactional注解的方法抛出的异常不是spring的事务支持的异常,导致事务失效
方式一:使用@Transactional(rollbackFor=Exception.class)指定拦截异常。
方式二:throw new RuntimeException("抛出运行时异常") 抛出spring事务支持的异常
spring的事务只支持未检查异常(unchecked),不支持已检查异常(checked)
4.数据表本身是不支持事务,导致事务失效
如果使用MySQL且存储引擎是MyISAM,则事务是不起作用的,原因是MyIASM不支持事务,
可以改为InnoDB存储引擎,支持事务。
5.@Transactional注解所在的类没有被spring管理,导致事务失效
未将类加入spring容器管理,例如未使用@Service @Component等,未使用其他能注册
成 Spring Bean的方式或注解。
6.捕获了异常之后,没有再次抛出异常,导致事务未拦截到异常,事务失效
如果在加有事务的方法内,使用了try…catch…语句块对异常进行了捕获,而catch语句块没有throw new RuntimeException异常或者Spring支持的异常类型,则事务不会回滚。
7.this调用问题,导致事务失效
情况一:同一类中,非事务方法使用this.调用事务方法
情况二:被调用方法重新开启了新的事务
原因:因为spring事务是基于AOP实现的,而AOP的实现是基于动态代理,this是自己调自己,并不存在代理对象的调用,这样AOP不起作用导致事务注解失效。
解决方法:
a.将被调用类放入其他类进行调用
b.自己注入自己,用注入的实例来调用
c.使用AopContext.currentProxy()将this调用改成动态代理调用
d.被调用的方法去掉事务注解,直接加入调用它的方法的事务里面
@Service
public class UserServiceImpl implements UserService{
// 自己注入自己
@Autowired
private UserService userService;
// 方式一
public void insert(User user){
// 调用方法
// 注意:这里不使用this调用,而是@Autowired自己(UserService)注入,然后调用事务方法
userService.insertUser(user);
}
// 方式二
public void insert(User user){
// 调用方法
// 获取代理类,利用代理类调用自己类的方法
UserServiceImpl proxy = (UserServiceImpl) AopContext.currentProxy();
proxy.insertUser(user);
}
@Transactional
@Override
public void insertUser(User user){
// 被调用方法
}
}
8.数据源没有配置事务管理器,导致事务失效
9.事务传播类型不支持事务,导致事务失效
例如:使用了@Transactional(propagation=Propagation.NOT_SUPPORTED)非事务方式等。
10.多线程调用,导致事务失效
两个方法不在同一个线程中,获取到的数据连接不一样,从而是两个不同的事务。我们说的
同一事务,实际是指同一数据库连接,拥有同一数据库连接才能同时提交和回滚。