需求:在插入数据后,查询插入的数据并发送MQ消息
1. @Transactional事务提交后执行异步任务
问题:我们在发送消息时如果事务未提交,此时异步方法中的select(id)方法是查询不到数据的
@Transactional(rollbackFor = Exception.class)
private void A() {
//插入一条记录
insert(student);
sendRabbitMq(student.getId());
}
/**
* 发送Mq消息
*/
@Async
private void sendRabbitMq(String id) {
Student student = select(id);
JSON.toJSONString(student);
String message = rabbitTemplate.convertAndSend(Exchange, "", message);
}
3 . 网上解决方案: TransactionSynchronization接口的afterCommit()方法,最终在事务commit提交后执行。
@Transactional(rollbackFor = Exception.class)
private void A() {
//插入一条记录
insert(student);
if(TransactionSynchronizationManager.isActualTransactionActive()) {
// 当前存在事务
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
executor.execute(() -> {
Student student = select(id);
JSON.toJSONString(student);
String message = rabbitTemplate.convertAndSend(Exchange, "", message);
//........
});
}});
} else {
// 当前不存在事务
executor.execute(() -> {
Student student = select(id);
JSON.toJSONString(student);
String message = rabbitTemplate.convertAndSend(Exchange, "", message);
});
}
}
4. 最终解决方案:因为需要用到线程池,所以在网上方案上进行部分修改 因为@Async注解修饰的方法是无法获取TransactionSynchronizationManager的 所以通过增加一个方法,在这个方法中获取事务管理器并调用多线程方法
@Transactional(rollbackFor = Exception.class)
private void A() {
//插入一条记录
insert(student);
sendRabbitMq(student.getId());
}
/**
* 用于获取事务处理器
*/
private void sendRabbitMq(String id) {
// 注册事务同步处理
if (TransactionSynchronizationManager.isActualTransactionActive()) {
//存在事物
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
sendRabbitMqAsync(String id)
}
});
} else {
sendRabbitMqAsync(String id)
}
}
/**
* 进行发送数据操作
*/
@Async("rabbitMqExecutor")
private void sendRabbitMqAsync(String id) {
Student student = select(id);
JSON.toJSONString(student);
String message = rabbitTemplate.convertAndSend(Exchange, "", message);
}
注意:方法A不能调用同一给类中使用了@Async注解的方法B(此时@Async会失效)
参考资料