@Transactional失效的场景及解决

1.@Transactional修饰的方法为非public方法,这个时候@Transactional会实现。
失败的原理是:@Transactional是基于动态代理来实现的,非public的方法,他@Transactional的动态代理对象信息为空,所以不能回滚。

2.在类内部没有添加@Transactional的方法,调用了@Transactional方法时,当你调用是,他也不会回滚
测试代码如下:

@Service
public class UserServiceImpl extends  implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    @Transactional
    public void insertOne() {
        User user = new User();
        user.setUsername("123");
        //插入到数据库
        userMapper.insert(user);
        //手动抛出异常
        throw new IndexOutOfBoundsException();
    } 
}

失败的原理:@Transactional是基于动态代理对象来实现的,而在类内部的方法的调用是通过this关键字来实现的,没有经过动态代理对象,所以事务回滚失效。

Spring框架的事务处理代码默认地只在抛出运行时和unchecked exceptions时才标识事务回滚。 也就是说,当抛出个RuntimeException 或其子类的实例时,(Errors 也一样 - 默认地 - 标识事务回滚。)

从事务方法中抛出的Checked exceptions将不被标识进行事务回滚。

解决办法:

在@Transactional中加上(rollbackFor = Exception.class) ==》@Transactional(rollbackFor = Exception.class)

3.就是在@Transactional方法内部捕获了异常,没有在catch代码块里面重新抛出异常,事务也不会回滚。

测试代码如下:

    @Override
    @Transactional
    public void insertOne() {
        try {
            User user = new User();
            user.setUsername("123");
            //插入到数据库
            userMapper.insert(user);
            //手动抛出异常
            throw new IndexOutOfBoundsException();
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
        }
    }

解决办法@Transactional的方法里面捕获了异常,手动回滚,
代码如下:

@Override
    @Transactional
    public void insertOne() {
        try {
            User user = new User();
            user.setUsername("123");
            //插入到数据库
            userMapper.insert(userEntity);
            //手动抛出异常
            throw new IndexOutOfBoundsException();
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }

4.创建表时,引擎是否是InnerDB

mysql数据库常用的引擎有两种(innodb和myisam),在建表时有些dba会默认使用myisam引擎,如果是这种引擎,那么在遇到异常时,数据库是不回滚的。所以将需要回滚的表引擎改为innodb

解决方法:

ALTER TABLE tableName CHANGE TYPE=InnoDB;
原文地址:https://www.cnblogs.com/mylqm/p/14926129.html