发现问题
最近开发中遇到一个问题,大致逻辑如下:service中有一个insert方法,在成功插入数据以后要发送kafka,kafak监听到消息后有相关的业务逻辑实现,该逻辑实现需要依赖之前insert插入的数据。
但是这里会存在一个bug:如果insert方法还没有进行事物提交,但是kafka已经监听到消息,此时查询数据库中是没有数据的,那后面的逻辑实现就没有了意义。所以必须保证insert语句成功提交数据以后才能发送kafka。
解决问题
使用TransactionSynchronizationManager.registerSynchronization
示例如下:
@Override
@Transactional
public Integer insert(Entity entity){
//示例代码
Integer result = mapper.insert(entity);
kafkaMessageSend("topic", entity.getId);
return result;
}
private void kafkaMessageSend(String topic, String message) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
kafkaTemplate.send(topic, message);
}
});
}
这是spring事务提供的注册回调接口的方法,通过该方法注册事务回调接口后,spring会在事务提交/回滚前后调用注册回调接口的对应方法。
- suspend:在spring开启新事务,获取connection之前会调用
- resume:开启新事务失败时会调用
- flush:没调用
- beforeCommit:事务提交前会调用
- beforeCompletion:事务提交前会调用,在beforeCommit之后
- afterCommit:事务提交后会调用
- afterCompletion:事务提交后会调用,在afterCommit之后
除了上述方法,还可以使用 @TransactionalEventListener 监听事务来实现。