添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

ps:因为周末有事情,所以本周的踩坑总结提前发啦~

我们在开启多线程对数据库进行操作的时候,先批量对数据进行删除,然后再新增,本来想着是考虑到不走更新,性能会提升,但是执行的时候发现报错,执行的sql等待超时,阻塞了进程,dbcp连接池被打满,数据库表访问不可用。针对这个问题,我们进行了深入的挖掘,逐渐解开了问题的真相。

复现准备工作

业务问题这里就不细讲了,为了方便讲解,操作直接简化。

  • 数据库表a有唯⼀索引t1,业务字段t2,主键id。数据库表a的定义如下:
  • 现在导⼊⼀批数据A的集合,A的定义如下所示:
  • 接下来复现问题操作

  • 根据t1的值查询表a中有没有对应的记录
  • 如果有值,则更新t2的值
  • 如果没查到结果,则执行insert插入操作 这里批量操作我们采用了多线程的方式来执行
  • 不走更新操作,先删除,后插入,保证只有2次数据库操作。

    从业务的⻆度考虑,表中只有id,t1,t2字段,且客户端实际也只关⼼t2字段。因此决定先根据A的t1字段去数据库⾥将对应的值删全部除,然后进⾏批量插⼊操作,这样的话,⽆论更新还是插⼊,都只有两次数据库操作,提高了性能。为了避免插⼊失败,导致数据被删除,在handle⽅法上添加事务。

    报错如下:

    Deadlock found when trying to get lock; try restarting transaction; nested exception is

    com.ibatis.common.jdbc.exception.NestedSQLException...

    可以看到,发⽣了数据库死锁。于是开始排查问题

    查询相关资料得知,引起死锁的原因是MYSQL的间隙锁。

    间隙锁(Gap Lock)是Innodb在可重复读提交下为了解决幻读问题时引⼊的锁机制,幻读的问题存在是因为新增或者更新操作,这时如果进⾏范围查询的时候(加锁查询),会出现不⼀致的问题,这时使⽤不同的⾏锁已经没有办法满⾜要求,需要对⼀定范围内的数据进⾏加锁,间隙锁就是解决这类问题的。在可重复读隔离级别下,数据库是通过⾏锁和间隙锁共同组成的(next-key lock)来实现的。

    ⾏锁和间隙锁的定义如下所示:

    record lock:⾏锁,也就是仅仅锁着单独的⼀⾏。

    gap lock:间隙锁,仅仅锁住⼀个区间(注意这⾥的区间都是开区间,也就是不包括边界值)。

    next-key lock:record lock+gap lock,所以next-key lock也就半开半闭区间,且是下界开,上界闭。

    加锁规则特性

    加锁规则有⼀些特性,其中我们需要关注的有:

    加锁的基本单位是(next-key lock),他是前开后闭原则

    查找过程中访问的对象会增加锁

    间隙锁仅阻⽌其他事务插⼊间隙。在删除数据的时候,会去加间隙锁,但是多个事务是可以同时对⼀个间隙去加锁的,⽽如果需要对该间隙进⾏插⼊,则需要等待锁释放。

    间隙锁复现死锁

    下⾯可以做个实验,去复现死锁问题。

    step1- ⾸先插⼊测试数据

    表a数据初始化后,这时候那么可能的next-key lock的包括:

    (⽆穷⼩, 10],(10,11],(11,13],(13,20],(20, ⽆穷⼤)

    step2- 我们开启两个窗⼝去模拟死锁。

    Session1:

    Session2:

    此时,Session 1和Session 2都会对区间(20, ⽆穷⼤)加锁, 因为间隙锁只是⽤来防⽌其他事务在区间中插⼊数据。

    step3- Session1继续插⼊操作:

    此时Session1阻塞(因为Session2持有间隙锁)。

    step4- 紧接着Session2继续插⼊操作:

    此时Session2死锁,因为Session1持有间隙锁。⽽我们的代码⾥⾯,因为涉及到多线程在事务⾥进⾏先删除后插⼊的操作,就会发⽣死锁。

    1、将事务隔离级别将为read commit.

    间隙锁只存在于可重复读的隔离级别下,因为要防⽌幻读。这个⽅法不现实,不可能为了这个问题 把整个线上数据库隔离级别给改掉。

    2、避免先删除后插⼊的操作.

    修改代码,避免先删除后插⼊的操作。牺牲性能,在业务中,先根据唯⼀索引查出存在的记录,然后对存在的记录进⾏根据主键Id在循环中更新,对于不存在的记录进⾏批量插⼊。

  • 2023前端面试题总结
  • 为什么B站的弹幕可以不挡人物
  • 三面面试官:运行 npm run xxx 的时候发生了什么?
  • 最近两周出去面试遇到的面试题(前端初级、长更)
  • 2022,前端的天🌦️要怎么变?
  • 10个常见的前端手写功能,你全都会吗?
  • 「万字总结」熬夜总结50个JS的高级知识点,全都会你就是神!!!
  •