美文网首页
spring声明式事务的一些坑

spring声明式事务的一些坑

作者: 一人_e0fb | 来源:发表于2018-08-08 19:34 被阅读25次

    总结

    1. 只支持public方法
    2. 无法支持内部调用

    场景和原理分析

    场景

    • 只支持public方法
        @Transactional
        public List<Area> getAreaList(int pageNo, int pageSize) {
            RowBounds rowBounds = new RowBounds(pageNo, pageSize);
            return areaMapper.getAreaList(rowBounds);
        }
    
    • 无法支持内部调用
    @Override
        public List<Area> getAreaList(int pageNo, int pageSize) {
            RowBounds rowBounds = new RowBounds(pageNo, pageSize);
            return areaMapper.getAreaList(rowBounds);
            transactionTest();
        }
        
        @Transactional
        public void transactionTest(){
            //假装有需要事务的操作
        }
    

    当然,idea还是很智能的


    idea提示

    原理分析

    我们都知道,spring的注解功能基本上都是通过spring aop,注解加切面才能完美的实现各种功能。当然,spring aop都是通过生成代理对象的方式实现的,也就是在代理对象中对你想要调用的方法进行了增强。
    反之而言,你不使用代理对象,注解无效。接下来看@Transactional的实现方式。
    在TransactionInterceptor中可以看到

    @Override
        public Object invoke(final MethodInvocation invocation) throws Throwable {
            // Work out the target class: may be {@code null}.
            // The TransactionAttributeSource should be passed the target class
            // as well as the method, which may be from an interface.
            Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
    
            // Adapt to TransactionAspectSupport's invokeWithinTransaction...
            return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
                @Override
                public Object proceedWithInvocation() throws Throwable {
                    return invocation.proceed();
                }
            });
        }
    

    而invokeWithinTransaction方法是使用调用TransactionAspectSupport中的方法,下面贴关键代码:

        // Standard transaction demarcation with getTransaction and commit/rollback calls.
                TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
                Object retVal = null;
                try {
                    // This is an around advice: Invoke the next interceptor in the chain.
                    // This will normally result in a target object being invoked.
                    retVal = invocation.proceedWithInvocation();
                }
                catch (Throwable ex) {
                    // target invocation exception
                    completeTransactionAfterThrowing(txInfo, ex);
                    throw ex;
                }
                finally {
                    cleanupTransactionInfo(txInfo);
                }
                commitTransactionAfterReturning(txInfo);
                return retVal;
    

    明显可以看到只是在方法前后进行了增强,也就是说内部调用方法未使用代理对象,无法进行增强也就无法开启事务。
    @Transactional 只能应用到 public 方法才有效
    只有@Transactional 注解应用到 public 方法,才能进行事务管理。这是因为在使用 Spring AOP 代理时,Spring 在调用在图 1 中的 TransactionInterceptor 在目标方法执行前后进行拦截之前,DynamicAdvisedInterceptor(CglibAopProxy 的内部类)的的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法会间接调用 AbstractFallbackTransactionAttributeSource(Spring 通过这个类获取表 1. @Transactional 注解的事务属性配置属性信息)的 computeTransactionAttribute 方法。如图:

    protected TransactionAttribute computeTransactionAttribute(Method method,
        Class<?> targetClass) {
            // Don't allow no-public methods as required.
            if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
    return null;}
    

    引用:https://www.ibm.com/developerworks/cn/java/j-master-spring-transactional-use/index.html

    相关文章

      网友评论

          本文标题:spring声明式事务的一些坑

          本文链接:https://www.haomeiwen.com/subject/rrbxbftx.html