【问题标题】:@Transactional on aspect advice possible?@Transactional 方面的建议可能吗?
【发布时间】:2011-08-01 02:13:24
【问题描述】:

我可以将@Transactional 标记应用于方面建议吗?我正在尝试使用方面在事务中包装对服务层(com.mycompany.app.myapp.service.*)的所有调用。我的方面是正确拦截对服务层的调用,但我不知道如何启动事务。我想我可以应用@Transactional 标签,因为我有标签,它会拿起它并开始交易。我错过了什么?

XML 配置:

<bean id="systemArchitectureAspect" class="com.mycompany.app.myapp.aspect.SystemArchitecture"/>
<bean id="transactionAspect" class="com.mycompany.app.myapp.aspect.MyAspect"/>

<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="transactionManager"  
    class="org.springframework.transaction.jta.JtaTransactionManager"> 
    <property name="transactionManager" ref="AtomikosTransactionManager" /> 
    <property name="userTransaction" ref="AtomikosUserTransaction" /> 
</bean> 

<bean id="AtomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"  
    init-method="init" destroy-method="close"> 

    <property name="forceShutdown" value="false" /> 
</bean> 

<bean id="AtomikosUserTransaction"  
    class="com.atomikos.icatch.jta.UserTransactionImp"> 
    <property name="transactionTimeout" value="10" />
</bean> 

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED" />
    </tx:attributes>
</tx:advice>

带有切入点的方面:

package com.mycompany.app.myapp.aspect;

@Aspect
public class SystemArchitecture {
    @Pointcut( "execution(* com.mycompany.app.myapp.service..*.*(..))" )
    public void inServiceLayer() {};

    @Pointcut( "execution(* com.mycompany.data..*.*(..))" )
    public void inDataAccessLayer() {};
}

我试图应用到我的切入点的建议:

package com.mycompany.app.myapp.aspect;

@Aspect
public class TransactionAspect {

    @Transactional
    @Around( "com.mycompany.app.myapp.aspect.SystemArchitecture.inServiceLayer()" )
    public Object interceptServiceLayer( ProceedingJoinPoint pjp ) throws Throwable
    {
        return pjp.proceed();
    }
}

【问题讨论】:

    标签: spring transactions aop aspectj


    【解决方案1】:

    robgmills

       @Transactional
        @Around( "com.mycompany.app.myapp.aspect.SystemArchitecture.inServiceLayer()" )
        public Object interceptServiceLayer( ProceedingJoinPoint pjp ) throws Throwable
        {
            return pjp.proceed();
        }
    

    你可以使用上面的 Around 建议,但需要做一些小改动。

    1. (propagation = Propagation.REQUIRES_NEW) 添加到@Transactional 在上面。
    2. @Transactional注解添加到您为其添加切入点inServiceLayer()的服务方法中。

    【讨论】:

      【解决方案2】:

      Spring 事务注解在运行时创建一个代理对象。因此,如果您在为服务提供建议的建议上应用事务注释,那么事务将针对建议而不是针对服务,因为建议适用于服务的代理对象,而您的事务注释将适用于服务的代理对象建议而不是建议的主要方法。理想情况下,您不应该获得作为服务功能扩展的建议。这违背了代理模式的目的。

      【讨论】:

        【解决方案3】:

        下面我有一个示例,说明如何将@TransactionalinServiceLayer() Pointcut 一起使用。我选择将正常流程与异常流程分开。这就是我不使用@Around 建议的原因。

        @Aspect
        public class TransactionAspect {
            private TransactionService transactionService = new TransactionServiceNull();
        
            @Pointcut( "execution(* com.mycompany.app.myapp.service..*.*(..))" )
            public void inServiceLayer() {};
        
            @Pointcut("execution(@org.springframework.transaction.annotation
                .Transactional * *(..))")
            public void transactionalMethod() {}
        
            @Before("transactionalMethod() && inServiceLayer()")
            public void beforeTransactionalMethod(JoinPoint joinPoint) {
                transactionService.beginTransaction();
            }
        
            @AfterReturning("transactionalMethod() && inServiceLayer()")
            public void afterTransactionalMethod(JoinPoint joinPoint) {
                transactionService.commit();
            }
        
            @AfterThrowing(pointcut = "transactionalMethod() && inServiceLayer()", 
                 throwing = "e")
            public void afterThrowingFromTransactionalMethod(JoinPoint joinPoint, 
                 RuntimeException e) {
                transactionService.rollback();
            }
        
            public void setTransactionService(
                final TransactionService transactionService) {
                this.transactionService = transactionService;
            }
        }
        

        在快速查看您的代码后,我不得不问您为什么用@Transactional 注释您的Pointcut?您应该只标记您希望在交易中执行的业务方法。

        我希望这会有所帮助!

        【讨论】:

        • 抱歉回复晚了,你给了我提示,我一直在运行以完成项目。使用 @Transactional 注释是让它工作的最后一次希望尝试。我不应该将它复制到示例代码中。感谢您的帮助!
        【解决方案4】:

        正如@Espen 所说,您应该直接在您的业务方法上应用@Transactional,因为注释本身会导致Spring 创建一个将事务应用于您的方法的方面。因此无需手动创建切面。

        但是,如果您想将事务应用于所有服务方法以及您使用这些切入点选择的任何其他内容,您应该使用 xml 配置来创建事务。 Look for declarative transaction management in the documentation

        另外,我认为您不能将@Transactional 应用于建议。至少它对我不起作用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-09-14
          • 2015-02-26
          • 2022-01-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多