Navicat 环境测试 innodb 的默认行锁升级表锁

时间:2022-07-27
本文章向大家介绍Navicat 环境测试 innodb 的默认行锁升级表锁,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

实验环境: 自己的是本机mysql 8.0 使用Navicat 15 窗口来进行会话实验。

之前被问到 行锁和表锁时:

我只知道 innodb 存储引擎 是支持行锁和表锁的,myIsam中 只支持表锁,(表锁的 排他锁好像也就是直接变成串行化的隔离级别了)。不知道什么情况下 行锁会升级为表锁。查看资料后,根据前人做过的经验 来测试一下锁升级的实验。

和上篇文章的实验表结构是一样的,强烈建议你直接用自己的表进行测试。

前提知识:

共享锁和排他锁 行锁和表锁

这个是我自己看别人的总结的

表锁和 行锁 按照功能分为 共享锁和排他锁。(也就是说行锁 表锁都有共享锁和排他锁)

共享锁:又称读锁,当一个事务对某几行上读锁时,允许其他事务对这几行进行读操作,但不允许其进行写操作,也不允许其他事务给这几行上排他锁,但允许上读锁。

排他锁:写锁:当这个事务对某几行上写锁时,不允许其他事务写,但允许读,更不允许其他事务进行上锁,包括读锁。

总结 : 也就是说 上了共享锁后 读锁后,这几行只能被读,不能被任何事务操作,其他事务可以上读锁,在第一个事务 结束后 也不可以修改,等我第二个事务结束提交后才能被修改。

而排他锁是当我这个事务上了锁之后 获得排他锁后只有获得这个锁的事务可以对 数据进行修改, 相比共享锁 读锁,还是可以修改的。

自己的实验表内容

其实和表内容没什么影响

原理说明:

  • 就给ip_address ='0:0:0:0:0:0:0:3' 行锁加 写锁排他锁, 如果是行锁的话就会 其他事务无法对当前行进行 修改 也不能对这行加 写锁 读锁 √
  • 但是其他事务我们对其他行 加写锁 读锁 修改数据 等都是 可以的对吧,因为是行锁,只所住了一行。 √
  • 因此如果现在因为我对非索引字段加锁,导致锁升级为表锁其他事务对其加读锁 写锁 和修改数据就会被堵塞,因为现在锁的处理细度变大 变成了表锁,那大家就一个一个事务来吧,行锁排他锁成为表锁的排他锁了 验证成为这样就说明锁进行了升级

总体执行步骤 在每次操作的后面,如数字一样表示可以随意执行哪个。

session 1 的全部操作

set autocommit  = 0   1

BEGIN    2


# 就给ip_address ='0:0:0:0:0:0:0:3' 行锁加 写锁排他锁, 如果是行锁的话就会对 其他事务无法对当前行进行 修改 也不能对这行加 写锁 读锁 √
# 但是其他事务我们对其他行 加写锁 读锁 修改数据 等都是 可以的对吧,因为是行锁,只所住了一行。 √
# 因此如果现在因为我对非索引字段加锁,导致锁升级为表锁,那大家就一个一个事务来吧,成为表锁的排他锁了 验证成为这样就说明锁进行了升级 
SELECT * FROM content   WHERE  ip_address ='0:0:0:0:0:0:0:3'  for UPDATE    3 



COMMIT 7

session2 的全部操作

4 5 6 操作 任意一个都可以证明结论


set autocommit  = 0    1


BEGIN    2
 
## 验证1  :修改数据,因为正常行锁:当其他事务锁定的是 ip_address 这一行的数据,我们对tcontent 行做更新 写操作是没问题的,
 
UPDATE content  set t_content = '测试锁升级,行锁升级为表锁1'   where tid = 246     4 

## 验证2 :加排他锁 因为正常行锁:当其他事务锁定的是 ip_address 这一行的数据,如果没有升级为表锁不会被阻塞等待,应该正常执行
SELECT * FROM content   WHERE  tid  = 246 for UPDATE         5


## 验证3 :加共享锁 因为正常行锁:当其他事务锁定的是 ip_address 这一行的数据,如果没有升级为表锁不会被阻塞等待,应该正常执行
SELECT * FROM content   WHERE  tid  = 246 lock in share MODE;         6


COMMIT     8

实验过程

首先执行session1 的 1 2 3

结果显示:很正常一次对非索引表字段的一次查询。

session2 从 三个验证 入手:三个任选一个就可以 都是在上面session1 事务未提交情况下执行的。

session2 执行 1 2 4 步骤

验证1 结果显示:被堵塞了

验证2 session2 执行 1 2 5 步骤

结果显示

验证3 session2 执行 1 2 6 步骤

结果显示

因此说明是进行了锁升级的过程。

实验收获:

行锁变表锁的情况:

  1. 行锁是建立在索引字段的基础上,如果行锁定的列不是索引列则会升级为表锁。(行锁 锁的是索引!!!)
  2. 索引列数据重复过多情况下,会导致索引失效,行锁变表锁。(像是唯一索引和 主键索引 这种唯一性大的不会变成,但数据重复率多的会变成)

尽量避免操作非索引的字段

参考文章

https://www.jianshu.com/p/477b7ccba3d2