39

由于某些原因,我使用 Spring PlatformTransactionManager 手动执行事务提交和回滚,我需要做的是设置一个挂钩,以便在事务提交后执行提交后操作。

通过查看:

 void commit(TransactionStatus status) throws TransactionException;

除了假设它之外,我看不到如何确定交易是否成功,所以如果没有抛出异常。

我可以使用 AOP 作为一种选择,但是如何以编程方式执行它,也许使用回调方法?

4

4 回答 4

74

你可以通过更简单的方式得到你想要的,使用TransactionSynchronizationManagerandTransactionSynchronization

使用TransactionSynchronizationManager,您可以使用静态方法来获取有关当前事务的信息,并且您可以注册一个TransactionSynchronization允许您在调用时自动执行 post-commit 的方法

TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization(){
           void afterCommit(){
                //do what you want to do after commit
           }
})

请注意,TransactionSynchronization 是基于每个线程的(这对于基本的 Web 请求通常不是问题)。

于 2013-02-22T14:49:40.347 回答
28

归功于 Grooveek 的回答和 Alex 在其下的评论 - 我把它放在这里是因为综合建议提供了一个在网络上很难找到的可靠和更清洁的解决方案。

使用 Spring 4+。如果您需要在@Transactional成功提交后对方法进行回调,只需在方法的开头添加:

@Service
public class OneService {

    @Autowired
    OneDao dao;

    @Transactional
    public void a transactionalMethod() {
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter(){
            public void afterCommit(){
                //do stuff right after commit
                System.out.println("commit!!!");

            }
        });
        //do db stuff
        dao.save();
    }
}
于 2017-04-10T11:31:53.747 回答
13

从 Spring 4.2 开始,可以使用基于注释的配置为提交后事件(或更一般的事务同步事件,例如回滚)定义侦听器。这是基于核心 spring中的事件处理。使用这种方法更容易测试代码,因为您避免了对 TransactionSynchronizationManager 的直接依赖,这在单元测试中可能不会处于活动状态。您可以轻松地测试您的事务服务是否发布了一个事件,以及您的侦听器在您收到事件时是否执行正确的操作。

因此,事不宜迟,这就是如何设置它:

在此示例中,我们假设您有一个Customer实体和一个CustomerRepository(以及与之配套的 ORM)。

首先你需要一个新的事件类型NewCustomerEvent

// NewCustomerEvent.java
// Just a regular pojo for the event
public class NewCustomerEvent {

    public String email;

    // constructor, setters and getters omitted
}

然后你定义一个监听器使用@TransactionalEventListener. 默认情况下,这将在成功提交后执行,但这可以使用phase参数进行更改:

// NewCustomerEventListener.java
@Component
public class NewCustomerEventListener {

    @TransactionalEventListener
    public void handleNewCustomerEvent(NewCustomerEvent newCustomerEvent) {
        // handle new customer event
    }
}

ApplicationEventPublisher最后,一旦发送了所有事务语句,您就可以使用您调用的发布来扩充您的事务服务。

// CustomerRespositoryService.java
@Service
public class CustomerRepositoryService {

    @Inject
    private ApplicationEventPublisher applicationEventPublisher;

    @Inject
    private CustomerRepository customerRepository;

    @Transactional
    public void createCustomer(String email) {
        Customer customer = new Customer(email);
        customerRespotory.save(customer);
        applicationEventPublisher.publish(new NewCustomerEvent(email));
    }

}

也可以看看:

于 2020-07-03T21:21:07.177 回答
1

在我的一个项目中,由于某些原因,我也不得不使用PlatformTransactionManager. 所以我被迫使用org.springframework.transaction.support.TransactionTemplate.

http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/transaction/support/TransactionTemplate.html

主要的好处是,如果你正确地实现了 PlatformTransactionManager,你就不需要手动提交/回滚了。如果您需要更具体的东西,至少 TransactionTemplate 的源代码可以帮助您。

使用起来非常简单:

配置文件

<bean name="transactionTemplate"
            class="org.springframework.transaction.support.TransactionTemplate">
    <property name="transactionManager" ref="platformTransactionManager"/>
</bean>

MyServiceImpl.java

@服务
公共类 MyServiceImpl 实现 MyService {

    @自动连线
    私人交易模板交易模板;

    公共实体 getSomethingWithTx(final long id) {

        返回 transactionTemplate.execute(new TransactionCallback<Entity>() {
            @覆盖
            公共实体doInTransaction(TransactionStatus状态){
                //TODO 实现
            }
        });
    }

于 2013-02-22T14:27:40.560 回答