下面详细讲解“Spring TransactionalEventListener事务未提交读取不到数据的解决”的完整攻略。
问题背景
在使用Spring框架中,如果在一个事务中,先进行数据库更新操作,并通过Spring事件机制进行监听处理,然后接着进行查询操作,此时可能会出现查询不到刚更新的数据的情况。这是因为事务未提交,更新的数据还没有提交到数据库,因此查询不到。
解决方案
事务的提交是一个关键点,而Spring中的TransactionalEventListener
是在事务提交后才会执行的,因此如果要在事务内部监听到刚更新的数据,则需要在事务内部再开一个子事务,将事件的发布放在子事务内部执行,等待子事务提交后再进行查询。
具体实现步骤如下:
第一步:定义监听器
首先,需要定义一个监听器类,用于监听事件。
@Component
public class DemoListener {
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleEvent(DemoEvent event) {
// 对更新后的数据进行处理
...
}
}
上述代码中,DemoListener
为监听器类,其中@TransactionalEventListener
注解表示该方法是一个监听方法,phase
表示监听时机,在本例中,使用TransactionPhase.AFTER_COMMIT
表示在事务提交后执行。当开启子事务执行该方法时,子事务提交后才会执行。
第二步:定义事件
接下来,需要定义一个事件类,用于表示数据更新的事件。
public class DemoEvent {
private String data;
public DemoEvent(String data) {
this.data = data;
}
public String getData() {
return data;
}
}
上述代码中,DemoEvent
为事件类,其中封装了更新后的数据,在监听器中可以通过该类获取更新后的数据。
第三步:开启子事务
在进行数据库更新操作后,需要使用Spring的TransactionTemplate
开启一个子事务,并通过ApplicationEventPublisher
发布事件,将事件发布到子事务内部执行。
@Autowired
private PlatformTransactionManager txManager;
@Autowired
private ApplicationEventPublisher eventPublisher;
public void updateDemoData() {
TransactionTemplate txTemplate = new TransactionTemplate(txManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
txTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
// 执行数据库更新操作
updateData(...);
// 发布事件
eventPublisher.publishEvent(new DemoEvent(...));
}
});
}
上述代码中,通过txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW)
设置事务传播机制为PROPAGATION_REQUIRES_NEW
,表示开启一个新的事务作为子事务。然后通过txTemplate.execute()
执行子事务的操作,包括数据库更新和事件发布。在子事务提交后,TransactionalEventListener
会在事务提交后进行处理,此时即可获取到刚更新的数据。
示例
下面是两个示例,分别展示了在事务内部监听和在事务外部监听的不同结果。
@Service
public class DemoService {
@Autowired
private DemoDao demoDao;
@Autowired
private DemoListener demoListener;
@Autowired
private ApplicationEventPublisher eventPublisher;
@Transactional
public void updateDataInside() {
demoDao.updateData(...);
eventPublisher.publishEvent(new DemoEvent(...));
demoListener.handleEvent(new DemoEvent(...));
demoDao.queryData(); // 可以查询到更新后的数据
}
@Transactional
public void updateDataOutside() {
demoDao.updateData(...);
eventPublisher.publishEvent(new DemoEvent(...));
demoDao.queryData(); // 查询不到更新后的数据
}
}
DemoService
为服务类,其中包含了两个方法,updateDataInside
和updateDataOutside
。在updateDataInside
方法中,使用子事务执行监听操作,此时可以查询到更新后的数据,而在updateDataOutside
方法中,未使用子事务,则查询不到更新后的数据。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring TransactionalEventListener事务未提交读取不到数据的解决 - Python技术站