在开发中是否遇到过这种情况,在一个spring事务管理的方法中需要发送一个消息,但是消费消息的时候查询到的数据还是事务提交之前的数据。
代码如下:
@Transactional
public void add() {
//插入数据逻辑
//发送消息
}
此时我们希望的效果是,等事务提交之后再发mq。
可以改成如下写法:
public void add() {
//insert方法
//发送消息
}
@Transactional
public void insert() {
//insert
}
但是这样每次涉及这样的业务都需要包一层,而且很多时候并不知道调用add文章的外层是否还有@Transactional
注解
我们希望达到的效果是注册一个mq事件,等事务提交后再出发我们的mq事件
。
TransactionSynchronizationManager
嵌入如下代码,可以注册一个事务事件,在事务提交之后才出发我的方法。
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
System.out.println("a");
}
});
总的写法如下:
@Transactional
public void add() {
//insert
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
//发送消息
}
});
}
这样消费消息时查到的数据就是最新的数据了。
还有一种编程式的事务应该也可以解决
public void add() {
transactionTemplate.execute(status -> {
});
// 发送消息
}
这种方式还可以用于批量执行时如果遇到错误或者异常不需要回滚的场景 , 不需要单独定一个service用于开启子事务或者动态代理获取当前的service了 , 直接将子事务中需要执行的逻辑用编程式的方式实现就好了。