@Transactional注解失效场景

 @Transitional注解用于完成声明式事务操作,默认当发生RuntimeException时会对当前事务操作进行回滚,但其使用不当就会造成失效;(注:若未使用该注解,或者未使用手动事务,则在进行数据库更新操作之后才抛出异常的话,该更新操作是不会被回滚的,即Spring默认没有异常回滚操作

场景一:抛出异常非RuntimeException

@Transitional
public void insert() throws Exception {

    // insert...
    throw new Exception();
}

解决方案

        手动设置事务回滚捕获的异常 

@Transactional(rollBackFor = Exception.class)
public void insert() throws Exception {
    // insert...
    throw new Exception();
}

场景二:方法类中自调用

被@Transactional注解的方法在类中自调用,是通过this对象进行的,而不是通过Cglib的代理对象调用,因此并没有被Spring事务处理器管理,从而导致事务失效。

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    publicvoid test1() {
        insertUser();
    }

    @Transactional(rollbackFor = Exception.class)
    public void insertUser() {
        User user = new User();
        userMapper.insert(user);
    }
}

解决方案:

        1、将@Transactional注解到外层方法

        2、如果业务避不开自调用,那么就自己注入自己,再进行调用;

方案一:
@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Transactional(rollbackFor = Exception.class)
    publicvoid test1() {
        insertUser();
    }

    public void insertUser() {
        User user = new User();
        userMapper.insert(user);
    }
}

方案二:
@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserService userService;

    publicvoid test1() {
        userService.insertUser();
    }
    
    @Transactional(rollbackFor = Exception.class)
    public void insertUser() {
        User user = new User();
        userMapper.insert(user);
    }
}

场景三:异常被捕获

异常被捕获后,没用继续抛出,导致Spring事务管理器没有捕捉到异常,其认为是正常业务逻辑,因而不会回滚。

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Transactional(rollbackFor = Exception.class)
    public void test1() {
        try {
            insertUser();
        } catch (Exception e) {
            System.out.println("测试解决异常");
        }
    }

    public void insertUser() throws Exception {
        User user = new User();
        user.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        user.setName(UUID.randomUUID().toString().replaceAll("-", ""));
        userMapper.insert(user);
        throw new Exception("test Exception");
    }
}

解决方案

        捕获解决后继续抛出。

@Transactional(rollbackFor = Exception.class)
public void test1() throws Exception {
    try {
        insertUser();
    } catch (Exception e) {
        System.out.println("测试解决异常");
        throw e;
    }
}

场景四:上游方法未使用事务,但是报错

        上游方法在调用下游方法时,上游方法未使用事务处理,而是在下游使用的事务,如果上游方法在调用事务方法之后报错了,则不会使下游事务方法回滚。

@Service
public class TestService {

    @Autowired
    private UserService userService;

    public void test() {
        userService.test1();
        int i = 1 / 0;    // 不会回滚
    }
}

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private TestService testService;

    public void test1() {
        insertUser();
    }

    public void insertUser() {
        User user = new User();
        user.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        user.setName(UUID.randomUUID().toString().replaceAll("-", ""));
        userMapper.insert(user);
    }
}


解决方案

        上游方法增加事务注解

@Service
public class TestService {

    @Autowired
    private UserService userService;

    @Transactional
    public void test() {
        userService.test1();
        int i = 1 / 0;
    }
}

其他场景

1、数据库引擎不支持事务,例如Mysql的MyIsam

2、@Transactional注解方法所在类未被Spring容器管理(未使用@Service等注解,取而代之使用new对象调用方法);

3、事务方法中存在异步业务,异步处理部分发生异常,不会使得主方法回滚。

        多线程事务处理可以参考文章:Spring在多线程环境下如何确保事务一致性icon-default.png?t=N7T8https://blog.csdn.net/m0_53157173/article/details/127423286
4、更多场景可查看:啪!啪!@Transactional 注解的12种失效场景,这坑我踩个遍-腾讯云开发者社区-腾讯云 (tencent.com)

某些事务失效还与Spring事务传播行为有关,这里不再展开,感兴趣小伙伴可以结合案例自行研究

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值