您现在的位置是:首页 >学无止境 >jpa事务失效的 场景网站首页学无止境

jpa事务失效的 场景

WuWuII 2024-06-14 17:19:22
简介jpa事务失效的 场景

jpa默认只有抛出RuntimeException,才会回滚,

1.异常被捕获

//不回滚
    public void delete(String id) {
        try {
            ptInterInfoDao.deleteById(id);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

这个catch只是输出了异常信息,并没有抛出,不会发生回滚,要把异常抛出,才会回滚

//回滚
    public void delete(String id) {
        try {
            ptInterInfoDao.deleteById(id);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }

2. 方法不是public

@Transactional注解只有修饰public方法时,事务才会生效,如果用在非public方法上,如protected、private,事务将失效。

3. 没有被Spring管理

类上面没有spring的注解,意味着当前类没有被Spring管理,事务自然就失效了。

4. 异常类型错误

@Transactional注解中,回滚的默认异常是RuntimeException,由于在saveUser()方法中抛出异常不是RuntimeException,导致当前事务不会回滚。若要使事务生效,使用@Transactional(rollbackFor = Exception.class)指定类型。

@Service
public class UserServiceImpl implements UserService {
    
    @Transactional
    public void saveUser(User user){
     throw new Exception("save user error");
    }
}

5. 自身调用问题

@Transactional的实现原理是AOP,而AOP的实现原理是动态代理,自己调用自己的过程,并不存在代理对象的调用,这样
就不会产生AOP去为我们设置@Transactional配置的参数,这样就出现了自调用注解失效的问题。

@Service
public class Test3 {

    @Transactional
    public void test1(){
        test2();
    }

    public void test2(){
        System.out.println(1/0);
    }

}

解决方法:

  1. 把自己注入进来,然后通过注入的对象调用方法

6. 传播类型不支持事务,导致事务失效

/以非事务方式运行
@Transactional(propagation Propagation.NOT_SUPPORTED)

Propagation.NOT SUPPORTED:表示不以事务运行,当前若存在事务则挂起,都主动不支持以事务方式运行了,那事务肯定就不生效了

7. 多线程调用,导致事务失效

两个方法不在同一个线程中,获取到的数据库连接不一样,从而是两个不同的事务。我们说的同一个事务,其实是指同一个数据库连接,只有拥有同一个数据库连接才能同时提交和回滚。如果在不同
的线程,拿到的数据库连接肯定是不一样的,所以是不同的事务。

8. 数据表本身是不支持事务,导致事务失效

如果使用MySQL且存储引擎是MyISAM,则事务是不起作用的,原因是MyIASM不支持事务。
数据表可以改为InnoDB存储引擎,支持事务

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。