Spring

【Spring】 11 - 关于 注解 配置 Spring AO

2020-10-25  本文已影响0人  itlu
  1. 问题 : 使用注解配置 Spring Aop 的四种通知类型实现事务控制,出现如下问题 :
  com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Can't call rollback when autocommit=true
  1. 原因:由于四种通知类型的执行顺序与 xml 配置方式的差异 ,可以将注解配置的方式理解为一个bug

  2. 正常使用 xml 配置 四种通知类型的执行顺序是 : 前置通知 后置通知/异常通知(当出现异常时) 最终通知。这是一种正常的情况。

     <aop:config>
        <aop:pointcut id="pc" expression="execution(* com.lyp.service.impl.*.*(..))"/>
        <aop:aspect id="txAspect" ref="txManager">
            <aop:before method="beginTransaction" pointcut-ref="pc"/>
            <aop:after-returning method="commitTransaction" pointcut-ref="pc"/>
            <aop:after-throwing method="rollbackTransaction" pointcut-ref="pc"/>
            <aop:after method="closeTransaction" pointcut-ref="pc"/>
        </aop:aspect>
    </aop:config>
  1. 使用注解配置四种通知类型的时候的执行顺序 :前置通知 最终通知 后置通知/异常通知(当出现异常时) 。此时最终通知优先于后置通知执行了,首先将连接释放,此时再进行提交,就是会出现上面的异常。
      /**
     * 开启事务
     */
    @Before("pc()")
    public void beginTransaction() {
        try {
            /* 设置事务提交方式为手动提交 */
            System.out.println("开启事务");
            cu.getTreadLocalConnection().setAutoCommit(false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 回滚事务
     */
    @AfterReturning("pc()")
    public void rollbackTransaction() {
        try {
            /* 设置事务提交方式为手动提交 */
            System.out.println("回滚事务...");
            cu.getTreadLocalConnection().rollback();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 提交事务
     */
    @AfterThrowing("pc()")
    public void commitTransaction() {
        try {
            System.out.println("提交事务....");
            /* 设置事务提交方式为手动提交 */
            cu.getTreadLocalConnection().commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 释放连接
     */
    @After("pc()")
    public void closeTransaction() {
        try {
            /* 设置事务提交方式为手动提交 */
            System.out.println("关闭事务....");
            cu.getTreadLocalConnection().close();
            cu.removeConn();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  1. 解决办法:使用环绕通知替换上面的配置
@Around("pc()")
public Object aroundAdvice(ProceedingJoinPoint pjp) {
        Object rs = null;
        try {
            Object[] args = pjp.getArgs();
            // 开启事务
            this.beginTransaction();
            // 执行代码
            rs = pjp.proceed(args);
            // 提交事务
            this.commitTransaction();
            return rs;
        } catch (Throwable t) {
            // 回滚事务
            this.rollbackTransaction();
            throw new RuntimeException(t);
        } finally {
            this.closeTransaction();
        }
    }
上一篇 下一篇

猜你喜欢

热点阅读