参考博客TransactionSynchronizationManager和TransactionSynchronizationAdapter
场景
业务流程背景:
对于“法律法规-法规库-标签管理”列表中的某一条数据,操作完标注和解析按钮后,我会更新该条数据的状态字段并向redis写入一条消息。web端开发从redis取消息会先判断一下该数据的状态字段看是否应该写入es,如果不应该,会告警。
问题原因:
由于改代码涉及多张表操作,故使用声明式事务,并在代码末尾异步往redis里写入消息。如果此时redis里面没消息,并且我这段代码事务提交耗时相当严重,会导致数据的状态我这边还未改变,然后web端开发取到消息他发现状态字段未发生改变,从而发出告警并且没有写入es。
假代码如下:
一种解决方法是:在异步的方法中手动延时操作,尽可能保证事务的提交。但是此时间并不好评估,非最优解。
二是:如果保证事务提交完成后,再去发送异步消息呢?
/**
* 新增保存用户信息
*
* @param user 用户信息
* @return 结果
*/
@Override
@Transactional(rollbackFor = Exception.class)
public int insertUser(SysUser user)
{
// 新增用户信息
int rows = userMapper.insertUser(user);
// 新增用户岗位关联
insertUserPost(user);
// 新增用户与角色管理
insertUserRole(user);
//如果有事务,则事务提交之后在执行
if (TransactionSynchronizationManager.isActualTransactionActive()) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
// todo 异步任务,如http请求,mq发送等
taskService.notifyEs("sys_user", "insert", user.getUserId().toString());
}
});
} else {
//没有事务,直接执行
taskService.notifyEs("sys_user", "insert", user.getUserId().toString());
}
try {
//模拟事务提交耗时
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return rows;
}