spring - 交易/提交后的番石榴事件总线发布
问题描述
我目前正在春季使用番石榴的事件总线,虽然到目前为止一般功能运行良好,但我遇到了以下问题:
当用户想要更改“线”实体上的数据时,这将在后端服务中照常处理。在此服务中,数据将首先通过 JPA 持久化,然后我创建一个“NotificationEvent”并引用已更改的实体。通过 EventBus,我将线路的引用发送给所有订阅者。
public void notifyUI(String lineId) {
EventBus eventBus = getClientEventBus();
eventBus.post(new LineNotificationEvent(lineId));
}
事件总线本身是在后台使用 new EventBus() 创建的。
现在在这种情况下,我的订阅者位于 @Transactional 领域之外的前端。因此,当我更改数据时,发布事件并让订阅者从数据库中获取所有必要的更新,实际事务尚未提交,这使得订阅者获取旧数据。
我能想到的唯一快速解决方法是异步处理它并等待一两秒钟。但是,在事务提交之后,还有其他方法可以使用 guava 发布事件吗?
解决方案
我认为番石榴根本没有“意识到”春天,尤其是没有“@Transactional”的东西。
所以你需要一个创造性的解决方案。我可以考虑的一种解决方案是将此代码移动到您确定事务已完成的位置。实现这一目标的一种方法是使用TransactionSyncrhonizationManager
:
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization(){
void afterCommit(){
// do what you want to do after commit
// in this case call the notifyUI method
}
});
请注意,如果事务失败(回滚)该方法将不会被调用,在这种情况下您可能需要afterCompletion
方法。查看文档
另一种可能的方法是将您的应用程序重构为如下所示:
@Service
public class NonTransactionalService {
@Autowired
private ExistingService existing;
public void entryPoint() {
String lineId = existing.invokeInTransaction(...);
// now you know for sure that the transaction has been committed
notifyUI(lineId);
}
}
@Service
public class ExistingService {
@Transactional
public String invokeInTransaction(...) {
// do your stuff that you've done before
}
}
我想在这里提到的最后一件事是,Spring 本身提供了一种事件机制,您可以使用它来代替 guava 的机制。
例如,请参阅本教程
推荐阅读
- python - 如何在python中断言所有断言失败
- reactjs - 更新嵌套数组中的对象,react-redux
- java - 如何解决recyclerview中按钮的自动点击问题?那是一个错误吗?
- javascript - Fullcalendar 事件属性验收
- linkedin - 如何从我是页面管理员的 LinkedIn 获取组织的帖子
- php - 我如何使用 curl 修复此登录
- python - pyzotero 批量更新字段
- python-3.x - 为什么python代码不能到达else语句?
- spring-boot - 我可以在 Spring Boot 1.5.x 中使用“Spring Data JDBC”吗?
- c - 为什么要打印两个指针相减的结果并抛出警告?