在单个类中正确使用多个事务的方法
在单个类中正确使用多个事务的方法
我正在使用Spring Boot。我可以使用@Transactional
在方法上强制使用事务。有时,我需要某些方法使用两个或更多的事务。
天真的方法不起作用:
public void doActions() { doAction1(); doAction2(); } @Transactional void doAction1() { ... } @Transactional void doAction2() { ... }
因为Spring使用代理来实现事务。
通常,我使用以下方法:
@Autowired private ThisService self; public void doActions() { self.doAction1(); self.doAction2(); } @Transactional void doAction1() { ... } @Transactional void doAction2() { ... }
它起作用了,但在Spring 2.6.0中,这种循环依赖导致应用程序启动失败,除非我将spring.main.allow-circular-references设置为true。
我真的不理解循环引用为什么不好。但显然,Spring Boot的开发人员不希望这种设计,所以我想我最好遵循他们的建议。
另一种方法是使用事务管理器并以编程方式调用事务API:
@Autowired private TransactionTemplate transactionTemplate; public void doActions() { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(@NonNull TransactionStatus status) { doAction1(); } }); transactionTemplate.execute(status -> { doAction2(); return null; });
它可以工作,但在我看来有点冗长和丑陋。
还有其他我错过的方法吗?我应该将spring.main.allow-circular-references设置为true吗?我担心开发人员将来会不支持这种循环引用,并且我可能需要重新设计我的应用程序。
在一个类中使用多个事务的正确方式
在某些情况下,我们可能需要在一个类中执行多个事务。然而,直接在一个类中使用多个事务可以导致代码变得混乱且难以维护。下面将介绍解决这个问题的原因和方法。
问题的原因:
直接在一个类中使用多个事务可能会导致代码难以阅读和维护。当代码中存在多个事务时,我们需要确保每个事务都被正确地管理和处理。此外,事务的传播行为也需要被明确指定,以确保事务的一致性和正确性。
解决方法:
为了解决在一个类中使用多个事务的问题,我们可以创建一个专门负责在事务中执行代码的服务类。这个服务类的工作类似于TransactionTemplate
,但它使用@Transactional
注解来管理事务。以下是一个示例代码:
public class TransactionExecutor { @Transactional(propagation = Propagation.REQUIRED) public <T> T execute(Supplier<T> action) { return action.get(); } @Transactional(propagation = Propagation.REQUIRED) public void execute(Runnable action) { action.run(); } @Transactional(propagation = Propagation.REQUIRES_NEW) public <T> T executeInNewTx(Supplier<T> action) { return action.get(); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void executeInNewTx(Runnable action) { action.run(); } }
然后,我们可以将这个服务类注入到需要使用多个事务的类中,例如:
public class FooService { private TransactionExecutor txExecutor; public void doActions() { txExecutor.execute(()->doAction1()); txExecutor.execute(()->doAction2()); } void doAction1() { ... } void doAction2() { ... } }
通过使用TransactionExecutor
类,我们可以更清晰地管理和处理多个事务。这样,我们可以确保每个事务都能根据需要进行正确的传播,并且代码更易于阅读和维护。