DB如下:
CREATE TABLE `tenant_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`created_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`updated_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `username_index` (`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=11794 DEFAULT CHARSET=utf8mb4;
多线程代码
@Transactional
public void insertOrUpdate(List<TenantUser> userList) {
log.info("当前线程 {}",Thread.currentThread().getId());
userList.forEach(source->{
TenantUser zhanghao = lambdaQuery().eq(TenantUser::getUsername, source.getUsername()).one();
if (Objects.nonNull(zhanghao)){
updateById(zhanghao);
}else {
save(source);
}
});
}
这种代码想必日常很经常见到,这个函数的数据会在所有的操作完成后统一提交事务,由于第一个查询是快照读,可能会产生幻读。 A执行读操作,读到快照,于是执行写操作,产生锁表 B线程的数据进入并且获取到了数据,于是执行更新,由于A线程执行insert异常,产生了s锁。此时B想要获取x锁进入等待。 A线程尝试获取X锁,此时前方有a的s锁和b的x锁都未释放,所以变成死锁。
Deadlock found when trying to get lock; try restarting transaction
|