前言
🎉兄弟们新年快乐呀🎉
今天小杨哥👨🦲过来说: “为啥我数据同步的时候一会儿正常,一会儿又有问题啊!”
我👦:“打开你的代码呢,你这事务还没提交执行完成,另一个事务就开始查询了都嘛,所以另一个事务查询的数据可能是 第一个事务提交前,或者是另一个事务提交后 都有可能”
本篇文章只有一个案例:分享了在事务中,开启新线程去处理任务引发的问题
问题代码
批量异步执行
业务逻辑: 我们的账号管理中心,需要对账号进行批量修改。修改完成之后需要将账号同步到各子系统。
实现方式: 因为同步逻辑有现成的方法,只是单个同步,现在因为要批量操作,因此调用同步逻辑就是开启新的线程,然后循环调用原来的单个同步方法。
问题代码
看一下service
的伪代码吧:
@Transactional(rollbackFor = Exception.class)
@Override
public Respoonse<String> updateAccountRoles(BatchUpdateParam param) {
//校验参数,
if(!paramCheck(param)){
return Response.fail("网络繁忙!");
}
// 更新账号信息。
List updateUserList = userService.updateRoles(param);
if (updateUserList.size() > 0) {
// 异步通知其他系统更新对应账号信息。
//❌事务还没提交,以及已经开始异步执行了,异步方法里面可能查询还是更新前的数据。
userSyncUtil.asyncUserList(updateUserList);
}
return Respoonse.ok("批量更新成功。");
}
❌事务还没提交,以及已经开始异步执行了,异步方法里面可能查询还是更新前的数据。
异步发送账号同步通知
public void asyncUserList(List<String> userIds) {
if (userIds == null || userIds.size() <= 0) {
return;
}
// 自定义线程就不推荐了
new Thread(() -> {
userIds.forEach(item -> this.sync(item));
}).start();
}
❌这个创建线程的方式就不推荐了
解决方案
- 将异步代码 注册到事务提交后的回调中
@Transactional(rollbackFor = Exception.class)
@Override
public Respoonse<String> updateAccountRoles(BatchUpdateParam param) {
//校验参数,
if(!paramCheck(param)){
return Response.fail("网络繁忙!");
}
// 更新账号信息。
List updateUserList = userService.updateRoles(param);
if (updateUserList.size() > 0) {
// 异步通知其他系统更新对应账号信息。
// 👍事务提交后执行
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
userSyncUtil.asyncUserList(updateUserList);
}
});
}
return Respoonse.ok("批量更新成功。");
}
- 控制事务范围
//❌删除外层事务
//@Transactional(rollbackFor = Exception.class)
@Override
public Respoonse<String> updateAccountRoles(BatchUpdateParam param) {
//校验参数,
if(!paramCheck(param)){
return Response.fail("网络繁忙!");
}
// 更新账号信息。👍 updateRoles 加事务注解就行了(或者用编程式事务)
List updateUserList = userService.updateRoles(param);
if (updateUserList.size() > 0) {
// 异步通知其他系统更新对应账号信息。
userSyncUtil.asyncUserList(updateUserList);
}
return Respoonse.ok("批量更新成功。");
}
总结
本篇文章只有一个案例,分享了在事务中,开启新线程去处理任务引发的问题。有时候这种问题可能在测试环节还不一定能复现,所以大家在开发中遇到这种问题,还不一定能快速定位到问题。
本篇文章虽然内容不多,但确实是开发过程中需要引起重视的。
ps 往期文章:
同事的代码问题(java) 同事的代码问题(第二期) 同事的代码问题(第三期)
同事的代码问题(第四期)