Seal^_^ 2025-12-05 09:15 采纳率: 91.2%
浏览 3
已采纳

@Transactional注解在同类方法调用时失效的根本原因是什么? 如何通过AspectJ的编译时织入解决此问题?

@Transactional注解在同类方法调用时失效的根本原因是什么? 如何通过AspectJ的编译时织入解决此问题?

  • 写回答

2条回答 默认 最新

  • 紫雾凌寒 新星创作者: 人工智能技术领域 2025-12-05 09:38
    关注

    让 “紫雾凌寒” 来帮你回答,本回答结合 DeepSeek

    如果还有问题,请评论或点击头像私信,如果有帮助到您, 请关注、采纳、点赞

    1. @Transactional注解在同类方法调用时失效的根本原因
      - Spring的事务是基于AOP实现的,在方法调用时会创建一个代理对象,通过代理对象来增强方法调用,从而实现事务管理。
      - 当在同类方法中调用被@Transactional注解的方法时,由于方法调用是直接通过对象实例进行的,而不是通过代理对象,所以事务增强不会生效。例如:
      ```java
      @Service
      public class TransactionService {
      @Transactional
      public void methodA() {
      // 执行一些业务逻辑
      methodB();
      }

      @Transactional
      public void methodB() {
      // 执行一些业务逻辑
      }
      }
      `` 在methodA中调用methodB时,不会经过代理对象,因此methodB上的@Transactional`注解不会起作用。

    2. 通过AspectJ的编译时织入解决此问题的方法
      - 引入依赖
      pom.xml中添加AspectJ相关依赖:
      xml <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.9.7</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7</version> </dependency>
      - 创建Aspect类
      ```java
      import org.aspectj.lang.ProceedingJoinPoint;
      import org.aspectj.lang.annotation.Around;
      import org.aspectj.lang.annotation.Aspect;
      import org.springframework.stereotype.Component;

      @Aspect
      @Component
      public class TransactionAspect {
      @Around(“@annotation(org.springframework.transaction.annotation.Transactional)”)
      public Object aroundTransactionalMethods(ProceedingJoinPoint joinPoint) throws Throwable {
      return joinPoint.proceed();
      }
      }
      - **配置AspectJ编译时织入**: 在`src/main/resources/META-INF/aop.xml`文件中添加如下配置:xml








      `` 这里`指定了要织入的包路径,根据实际情况修改。

    3. 各种解决方案的优缺点
      - 使用AspectJ编译时织入

      • 优点
      • 能够真正在编译阶段织入切面逻辑,对性能影响较小。
      • 可以确保事务在同类方法调用时也能生效,解决了Spring AOP在同类方法调用时事务失效的问题。
      • 缺点
      • 配置相对复杂,需要引入AspectJ的相关依赖和进行额外的配置。
      • 对代码结构有一定侵入性,需要创建Aspect类和配置文件。
      • 使用CGLIB代理
      • 优点
      • 不需要像AspectJ那样复杂的配置,相对简单。
      • 缺点
      • 性能上可能会有一定损耗,因为CGLIB代理创建代理对象有一定开销。
      • 不能完全解决同类方法调用时事务失效的问题,只是通过代理调用的方式尽量避免直接调用。
    4. 总结
      - @Transactional注解在同类方法调用时失效是因为直接方法调用绕过了代理对象。
      - 通过AspectJ的编译时织入可以有效解决此问题,虽然配置相对复杂,但能确保事务在各种情况下生效,对性能影响较小。不同的解决方法各有优缺点,在实际应用中可根据项目的具体需求和特点来选择合适的方案。

    希望以上解答对您有所帮助。如果您有任何疑问,欢迎在评论区提出。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 已采纳回答 3月26日
  • 创建了问题 12月5日