Mysql行锁引发的问题

数据表结构:

在这里插入图片描述

事物隔离级别(可重复读):

在这里插入图片描述

业务场景:

需要在内存中处理大量数据,处理完后保存数据库。**

演示代码:
在这里插入图片描述

一、对tb_pv表进行条件删除( ip=1);
二、开启一个线程对tb_pv表进行新增包含字段(ip=1),线程join等待线程one执行完后再执行主线程;
三、调用后线程后,线程一直等待;
四、查询一下数据库发现出现两个锁了,都指向tb_pv表;如下

SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
在这里插入图片描述

五、等待片刻,超时后出现错误;如下
在这里插入图片描述

问题分析:

直接模仿代码操作mysql

一、同样开启一个事物,删除tp_pv ip=’1’的记录;(不提交也不回滚)

在这里插入图片描述

二、模仿线程操作一tb_pv ip=’1’进行新增,发现插入不了,出现和代码执行后的错误一样;

在这里插入图片描述
三、插入|删除一条和ip=’1’不相关的记录,发现也是执行不了;

在这里插入图片描述

在这里插入图片描述
四、在插入时候查询一下数据库的锁,发现和代码执行的一样,有两个锁,都对应着tb_pv
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;

在这里插入图片描述

五、把删除操作回滚,发现插入操作ok了

在这里插入图片描述
在这里插入图片描述

问题:

在这里插入图片描述
在这里插入图片描述

在插入的时候出现了两个排它锁,并且都是行锁,为什么插入和ip!=’1’也不成功呢,lock_space、lock_page、lock_rec代表锁中了一行为第3页表空间 ID为230。

六、在tb_pv表中加入主键id,使用主键删除,并且调用insert发现是ok的;

在这里插入图片描述
在这里插入图片描述

以此推论在范围删除时,数据库其实是锁着了表的一部分(间隙锁),只有在删除指定唯一数据的时候才是锁行;
后面发现间隙锁是有两个触发条件;如果不符合,实际上是实行了表锁;详细的可以了解mysql数据结构和锁;
间隙锁条件:
1、隔离级别是可重复读;
2、必须是有索引;

解决方法

1、直接把锁住的事物结束;
查询事物
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
在这里插入图片描述
关闭
kill trx_mysql_thread_id;

2、将代码拆分,把删除操作单独起一个事物,不存在原来的事物中。
设置@Transactional(propagation = Propagation.REQUIRES_NEW),@Transactional默认是Propagation.REQUIRED,如果父方法调子方法都存在@Transactional注解,则会把子方法的事物默认加入到父方法的事物中,而加入propagation = Propagation.REQUIRES_NEW意思是,创建一个新事务,如果当前存在事务,将这个事务挂起。也就是说如果当前存在事务,那么将当前的事务挂起,并开启一个新事务去执行REQUIRES_NEW标志的方法。这样就能防止去同时获取锁。
在这里插入图片描述

3、业务放入线程处理,处理完把数据返回出来,再保存。

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值