在单个类中正确使用多个事务的方法

8 浏览
0 Comments

在单个类中正确使用多个事务的方法

我正在使用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吗?我担心开发人员将来会不支持这种循环引用,并且我可能需要重新设计我的应用程序。

0
0 Comments

在一个类中使用多个事务的正确方式

在某些情况下,我们可能需要在一个类中执行多个事务。然而,直接在一个类中使用多个事务可以导致代码变得混乱且难以维护。下面将介绍解决这个问题的原因和方法。

问题的原因:

直接在一个类中使用多个事务可能会导致代码难以阅读和维护。当代码中存在多个事务时,我们需要确保每个事务都被正确地管理和处理。此外,事务的传播行为也需要被明确指定,以确保事务的一致性和正确性。

解决方法:

为了解决在一个类中使用多个事务的问题,我们可以创建一个专门负责在事务中执行代码的服务类。这个服务类的工作类似于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类,我们可以更清晰地管理和处理多个事务。这样,我们可以确保每个事务都能根据需要进行正确的传播,并且代码更易于阅读和维护。

0