Spring基于注解的AOP事务控制报错:Can‘t call commit when autocommit=true

Spring基于注解的AOP事务控制报错:Can’t call commit when autocommit=true

结论

没有考虑spring基于注解的AOP通知的执行顺序。

正文

当使用注解配置AOP时,在配置完四大通知(前置通知,后置通知,异常通知,最终通知)后,如下

package com.item.utils;

import com.sun.tracing.dtrace.Attributes;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import java.sql.SQLException;

/**
 * 和事务相关的工具类,它包含了,开启事务,提交事务,回滚事务和释放连接
 */
@Aspect
@EnableAspectJAutoProxy
@Component("txManger")
public class TransactionManager {
    @Autowired
    private ConnectionUtils connectionUtils;
    @Pointcut("execution(* com.item.service.impl.AccountServiceImpl.*(..))")
    private void pt1(){}
    /**
     * 开启事务
     */
    @Before("pt1()")
    public void beginTransaction(){
        System.out.println("Before执行");
        System.out.println();
        try {
            connectionUtils.getThreadConnection().setAutoCommit(false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 提交事务
     */
    @AfterReturning("pt1()")
    public void commitTransaction(){
        System.out.println("AfterReturning执行");
        try {
            connectionUtils.getThreadConnection().commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    /**
     * 回滚事务
     */
    @AfterThrowing("pt1()")
    public void rollbackTransaction(){
        System.out.println("AfterThrowing执行");
        try {
            connectionUtils.getThreadConnection().rollback();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    /**
     * 释放连接
     */
    @After("pt1()")
    public void releaseTransaction(){
        System.out.println("After执行");
        try {
            connectionUtils.getThreadConnection().close(); //还回连接池中
            connectionUtils.removeConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

然而在执行的时候却出异常。经过排查得知,没有考虑Spring基于注解AOP配置的执行顺序问题。
在这里插入图片描述
我们设想的是:前置通知 --> 切入点方法–> 后置通知 / 异常通知 --> 最终通知
然而实际运行则是:前置通知 --> 切入点方法 --> 最终通知 --> 后置通知 /异常通知

在实际运行中,connection在执行最终通知后,就已经结束了本次提交。然而此时后置通知/异常通知还未执行,所以又从连接池中获取了一个新的连接,此连接没有关闭自动提交,所以此时报错。

解决方法:

1、配置基于XML的AOP

<aop:aspectj-autoproxy ></aop:aspectj-autoproxy>
    <aop:config>
            <aop:pointcut id="pt1" expression="execution(* com.item.service.impl.AccountServiceImpl.*(..))"/>
            <aop:aspect ref="txManager">
                <aop:before method="beginTransaction" pointcut-ref="pt1"></aop:before>
                <aop:after-returning method="commitTransaction" pointcut-ref="pt1"></aop:after-returning>
                <aop:after-throwing method="rollbackTransaction" pointcut-ref="pt1"></aop:after-throwing>
                <aop:after method="releaseTransaction" pointcut-ref="pt1"></aop:after>
            </aop:aspect>
        </aop:config>

2、配置基于环绕通知的AOP

   @Around("pt1()")
    public Object aroundNotif(ProceedingJoinPoint pjp){
        Object returnVal = null;
        Object[] args = pjp.getArgs();
        try {
            beginTransaction(); //前置通知
            returnVal = pjp.proceed(args);
            commitTransaction();//后置通知
            return returnVal;
        } catch (Throwable throwable) {
            rollbackTransaction();//异常通知
            throw new RuntimeException(throwable);
        }finally {
            releaseTransaction();//最终通知
        }
    }

配置完成后程序顺利执行!
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值