您好,欢迎访问代理记账网站
移动应用 微信公众号 联系我们

咨询热线 -

电话 15988168888

联系客服
  • 价格透明
  • 信息保密
  • 进度掌控
  • 售后无忧

多线程下mysql的死锁问题

  • 版本5.7
  • 数据隔离级别默认RR

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执行读操作,读到快照,于是执行写操作,会导致Duplicate entry异常。
B线程的数据进入并且获取到了数据,于是执行更新,由于A线程执行insert异常,产生了s锁。此时B想要获取x锁进入等待。
C线程尝试获取X锁,此时前方有a的s锁和b的x锁都未释放,所以变成死锁。


分享:

低价透明

统一报价,无隐形消费

金牌服务

一对一专属顾问7*24小时金牌服务

信息保密

个人信息安全有保障

售后无忧

服务出问题客服经理全程跟进