Spring @Transaction方法由同一类内的方法调用,不起作用?使用 AspectJ 处理事务的配置提示

2022-08-31 07:07:13

我是春季交易的新手。我发现这真的很奇怪,也许我确实正确地理解了这一点。

我想在方法级别上有一个事务性,并且在同一类中有一个调用方方法,它似乎不像那样,它必须从单独的类中调用。我不明白这怎么可能。

如果有人知道如何解决此问题,我将不胜感激。我想使用相同的类来调用带注释的事务方法。

代码如下:

public class UserService {

    @Transactional
    public boolean addUser(String userName, String password) {
        try {
            // call DAO layer and adds to database.
        } catch (Throwable e) {
            TransactionAspectSupport.currentTransactionStatus()
                    .setRollbackOnly();

        }
    }

    public boolean addUsers(List<User> users) {
        for (User user : users) {
            addUser(user.getUserName, user.getPassword);
        }
    } 
}

答案 1

这是Spring AOP(动态对象和cglib)的限制

如果您将Spring配置为使用AspectJ来处理事务,则您的代码将起作用。

简单且可能是最好的替代方法是重构代码。例如,一个处理用户的类和一个处理每个用户的类。然后,使用Spring AOP的默认事务处理将起作用。


使用 AspectJ 处理事务的配置提示

要使 Spring 能够将 AspectJ 用于事务,必须将模式设置为 AspectJ:

<tx:annotation-driven mode="aspectj"/>

如果您将Spring与3.0之前的版本一起使用,则还必须将其添加到Spring配置中:

<bean class="org.springframework.transaction.aspectj
        .AnnotationTransactionAspect" factory-method="aspectOf">
    <property name="transactionManager" ref="transactionManager" />
</bean>

答案 2

在Java 8 +中还有另一种可能性,由于以下原因,我更喜欢这种可能性:

@Service
public class UserService {

    @Autowired
    private TransactionHandler transactionHandler;

    public boolean addUsers(List<User> users) {
        for (User user : users) {
            transactionHandler.runInTransaction(() -> addUser(user.getUsername, user.getPassword));
        }
    }

    private boolean addUser(String username, String password) {
        // TODO call userRepository
    }
}

@Service
public class TransactionHandler {

    @Transactional(propagation = Propagation.REQUIRED)
    public <T> T runInTransaction(Supplier<T> supplier) {
        return supplier.get();
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public <T> T runInNewTransaction(Supplier<T> supplier) {
        return supplier.get();
    }
}

此方法具有以下优点:

  1. 它可以应用于私有方法。因此,您不必仅仅为了满足Spring的限制而公开方法来破坏封装。

  2. 可以在不同的事务传播中调用相同的方法,并且由调用方选择合适的方法。比较以下 2 行:

    transactionHandler.runInTransaction(() -> userService.addUser(user.getUserName, user.getPassword));

    transactionHandler.runInNewTransaction(() -> userService.addUser(user.getUserName, user.getPassword));

  3. 它是明确的,因此更具可读性。


推荐