springboot事务中的一些坑

springboot开启声明式事务方式

  • 在Application启动类中加入注解@EnableTransactionManagement(mode = AdviceMode.PROXY)
  • 在需要加入事务的方法上加入注解@Transactional
  • @Transactional(rollbackFor = RollbackException.class) 抛出指定异常时回滚
    /**
     * <p>
     *      (rollbackFor = RollbackException.class) 抛出自定义异常时,回滚事务。
     * </p>
     * @throws RollbackException
     */
    @Override
    @Transactional(rollbackFor = RollbackException.class)
    public void insertThenRollback() throws RollbackException {
        jdbcTemplate.execute("INSERT INTO Student (NAME) VALUES ('Tom')");
        throw new RollbackException();
    }

常见问题

例如有这个实现类StudentServiceImpl:

@Component
public class StudentServiceImpl implements StudentService {

    /**
     * <p>
     *      (rollbackFor = RollbackException.class) 抛出自定义异常时,回滚事务。
     * </p>
     * @throws RollbackException
     */
    @Override
    @Transactional(rollbackFor = RollbackException.class)
    public void insertThenRollback() throws RollbackException {
        jdbcTemplate.execute("INSERT INTO Student (NAME) VALUES ('BBB')");
        throw new RollbackException();
    }
    
        /**
     * <p>
     *      spring的事务是通过aop进行代理增强的。
     *      这里是在类的内部直接执行方法调用,并没有调用代理类来进行方法调用,所以这里事务不会回滚。
     * </p>
     *
     * @throws RollbackException
     */
    @Override
    public void invokeInsertThenRollback1() throws RollbackException {
        insertThenRollback();
    }
    
}

上面的insertThenRollback()回回滚事务,invokeInsertThenRollback1()调用了insertThenRollback()方法但是不会回滚事务,这是为什么呢?
这是因为spring的事务是通过aop进行代理增强的,但这里是在类的内部直接执行方法调用,并没有调用代理类来进行方法调用,所以这里事务不会回滚。

解决办法

  • 第一种方法:通过AopContext.currentProxy()获取当前类的代理对象。
    /**
     *
     * 通过AopContext.currentProxy()获取当前类的代理对象
     *
     * @throws RollbackException
     */
    @Override
    public void invokeInsertThenRollback2() throws RollbackException {
        ((StudentService) (AopContext.currentProxy())).insertThenRollback();
    }
  • 第二种方法:把自己的实例注入进来,让spring为我们创建代理。
    //把自己的实例注入进来
    @Autowired
    private StudentService studentService;
    
    
    /**
     * 把自己的实例注入进来
     * @throws RollbackException
     */
    @Override
    public void invokeInsertThenRollback3() throws RollbackException {
        studentService.insertThenRollback();
    }
posted @ 2019-09-04 22:29  monkjavaer  阅读(3351)  评论(0编辑  收藏  举报