服务内部调用事务this.test()事务会失效,你有几种解决方式?

@Transactional public void test() { // 事务操作 } this.test()事务会失效,那在service中自己注入自己再调用test,事务可以生效吗?

1 个回答

  • 小王子-B528
    你爱你的玫瑰是因为你在你的玫瑰上花了太多的时间!
    常见的 5 种方法: ### 1. 自己注入自己 通过 Spring 的依赖注入机制,将当前类的代理对象注入到自身的属性中,再通过该代理对象调用事务方法,使得 `@Transactional` 生效。 示例: ```java @Service public class MyService { @Autowired private MyService self; // 注入自身 @Transactional public void test() { System.out.println("事务方法执行"); // 事务操作 } public void execute() { self.test(); // 通过代理对象调用事务方法 } } ``` 优点:简单易用,改动较少。 缺点:可能引发循环依赖问题,尤其是在复杂场景中。 ### 2. 使用 AopContext 获取代理对象 通过 Spring 提供的 `AopContext` 获取当前类的代理对象,避免直接使用 `this` 调用。 示例: ```java @EnableAspectJAutoProxy(exposeProxy = true) // 必须开启此配置 @Service public class MyService { @Transactional public void test() { System.out.println("事务方法执行"); // 事务操作 } public void execute() { MyService proxy = (MyService) AopContext.currentProxy(); // 获取代理对象 proxy.test(); // 调用代理对象的方法 } } ``` 优点:不需要注入自身,避免了循环依赖问题。 缺点:依赖 Spring AOP 配置,需显式开启 `exposeProxy`。 ### 3. 使用 ApplicationContext 获取代理对象 从 Spring 容器中获取当前类的代理对象,利用 Spring 的 Bean 管理特性。 示例: ```java @Service public class MyService { @Autowired private ApplicationContext applicationContext; @Transactional public void test() { System.out.println("事务方法执行"); // 事务操作 } public void execute() { MyService proxy = applicationContext.getBean(MyService.class); // 从容器中获取代理对象 proxy.test(); // 调用代理对象的方法 } } ``` 优点:避免直接注入自身,解决循环依赖问题。 缺点:对容器有一定依赖,代码侵入性稍高。 ### 4. 使用代理工厂获取代理对象 封装一个代理工厂类,用于动态获取当前类的代理对象,适用于多个类需要类似逻辑的场景。 示例: ```java @Component public class ProxyFactory { @Autowired private ApplicationContext applicationContext; public <T> T getProxy(Class<T> clazz) { return applicationContext.getBean(clazz); } } @Service public class MyService { @Autowired private ProxyFactory proxyFactory; @Transactional public void test() { System.out.println("事务方法执行"); // 事务操作 } public void execute() { MyService proxy = proxyFactory.getProxy(MyService.class); // 使用工厂获取代理对象 proxy.test(); // 调用代理对象的方法 } } ``` 优点:通用性高,可在多个类中复用。 缺点:增加了一层工厂封装,略微复杂。 ### 5. 重构代码,拆分类 将事务方法从当前类中抽取到另一个类,由调用方注入该类并调用事务方法,符合单一职责原则。 示例: ```java @Service public class TransactionalService { @Transactional public void test() { System.out.println("事务方法执行"); // 事务操作 } } @Service public class MyService { @Autowired private TransactionalService transactionalService; public void execute() { transactionalService.test(); // 调用其他类的事务方法 } } ``` 优点:设计清晰,符合面向对象原则。 缺点:需要调整类设计,改动较大。 ### 解决方案对比 | **方案** | **优点** | **缺点** | **适用场景** | |--------------------|--------------------------------------------|------------------------------------------|---------------------------------| | 自己注入自己 | 简单易用,改动少 | 可能引发循环依赖 | 代码较简单的场景 | | 使用 AopContext | 避免循环依赖,避免注入自身 | 需要开启 `exposeProxy` | 对 AOP 依赖较高的场景 | | 使用 ApplicationContext | 避免循环依赖,解决事务问题 | 对容器依赖较高,代码侵入性稍强 | 不愿修改代理配置的场景 | | 使用代理工厂 | 通用性强,可复用 | 增加了一层封装,复杂度略高 | 多个类需要类似逻辑的场景 | | 重构代码,拆分类 | 符合设计原则,避免事务失效 | 改动较大 | 长期维护的大型系统 | 根据具体项目需求和代码复杂度,可以选择适合的解决方案。如果可能,推荐 **重构代码拆分类**,以提升代码的可维护性和设计质量。
    发布于 2024-11-28 07:21 •IP属地 陕西
    举报
    评论
    收藏