实验环境: 自己的是本机mysql 8.0 使用Navicat 15 窗口来进行会话实验。
之前被问到 行锁和表锁时:
我只知道 innodb 存储引擎 是支持行锁和表锁的,myIsam中 只支持表锁,(表锁的 排他锁好像也就是直接变成串行化的隔离级别了)。不知道什么情况下 行锁会升级为表锁。查看资料后,根据前人做过的经验 来测试一下锁升级的实验。
和上篇文章的实验表结构是一样的,强烈建议你直接用自己的表进行测试。
前提知识:
共享锁和排他锁 行锁和表锁
这个是我自己看别人的总结的
表锁和 行锁 按照功能分为 共享锁和排他锁。(也就是说行锁 表锁都有共享锁和排他锁)
共享锁:又称读锁,当一个事务对某几行上读锁时,允许其他事务对这几行进行读操作,但不允许其进行写操作,也不允许其他事务给这几行上排他锁,但允许上读锁。
排他锁:写锁:当这个事务对某几行上写锁时,不允许其他事务写,但允许读,更不允许其他事务进行上锁,包括读锁。
总结 : 也就是说 上了共享锁后 读锁后,这几行只能被读,不能被任何事务操作,其他事务可以上读锁,在第一个事务 结束后 也不可以修改,等我第二个事务结束提交后才能被修改。
而排他锁是当我这个事务上了锁之后 获得排他锁后只有获得这个锁的事务可以对 数据进行修改, 相比共享锁 读锁,还是可以修改的。
自己的实验表内容
其实和表内容没什么影响
原理说明:
- 就给ip_address ='0:0:0:0:0:0:0:3' 行锁加 写锁排他锁, 如果是行锁的话就会 其他事务无法对当前行进行 修改 也不能对这行加 写锁 读锁 √
- 但是其他事务我们对其他行 加写锁 读锁 修改数据 等都是 可以的对吧,因为是行锁,只所住了一行。 √
- 因此如果现在因为我对非索引字段加锁,导致锁升级为表锁,其他事务对其加读锁 写锁 和修改数据就会被堵塞,因为现在锁的处理细度变大 变成了表锁,那大家就一个一个事务来吧,行锁排他锁成为表锁的排他锁了 验证成为这样就说明锁进行了升级
总体执行步骤 在每次操作的后面,如数字一样表示可以随意执行哪个。
session 1 的全部操作
代码语言:javascript复制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 操作 任意一个都可以证明结论
代码语言:javascript复制
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 步骤
结果显示
因此说明是进行了锁升级的过程。
实验收获:
行锁变表锁的情况:
- 行锁是建立在索引字段的基础上,如果行锁定的列不是索引列则会升级为表锁。(行锁 锁的是索引!!!)
- 索引列数据重复过多情况下,会导致索引失效,行锁变表锁。(像是唯一索引和 主键索引 这种唯一性大的不会变成,但数据重复率多的会变成)
尽量避免操作非索引的字段
参考文章
https://www.jianshu.com/p/477b7ccba3d2