spring事物失效场景

java 开发中,如果一个请求需要操作多个数据表(增删改),为了确保操作的原子性,数据的一致性,一般需要引入spring事物注解@Transactional。

事物特性:ACID (原子性 一致性  隔离性 持久性)

失效场景1: 访问权限不支持  

java 中访问权限有 private ,default, protect, public ,要想事物生效,spring 要求被代理的方法必须是public修饰的。

失效场景2:方法用final 修饰

被final 修饰的方法表示该方法不可被子类重写。 spring 事务底层使用了 aop,通过 jdk 动态代理或者 cglib,帮我们生成了代理类,在代理类中实现的事务功能。但如果某个方法用 final 修饰了,那么在它的代理类中,就无法重写该方法,无法实现事物。

失效场景3:方法内部调用

例如: updateStatus 事物并不会生效,updateStatus会被当成add方法的this调用,并没有加入spring 代理中。

@Servicepublic class UserService {    @Autowired    private UserMapper userMapper;      public void add(UserModel userModel) {        userMapper.insertUser(userModel);        updateStatus(userModel);    }    @Transactional    public void updateStatus(UserModel userModel) {        doSameThing();    }}

解决办法: 使用AopContext.currentProxy() 获取代理对象    ((UserService)AopContext.currentProxy()).updateStatus(userModel);

失效场景4:多线程调用
只有拥有同一个数据库连接才能同时提交和回滚。如果在不同的线程,拿到的数据库连接肯定是不一样的,所以是不同的事务。

失效场景5:数据库表不支持事物
如果表引擎是myisam 则不支持事物,mysql5之后innodb 取而代之。

失效场景6:try catch 吞并了异常或抛出了其他异常

 spring 事务,默认情况下只会回滚RuntimeException(运行时异常)和Error(错误),对于普通的 Exception(非运行时异常),它不会回滚。

@Slf4j@Servicepublic class UserService {        @Transactional    public void add(UserModel userModel) throws Exception {        try {             saveData(userModel);             updateData(userModel);        } catch (Exception e) {            log.error(e.getMessage(), e);            throw new Exception(e);        }    }}