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 步骤
结果显示
因此说明是进行了锁升级的过程。
实验收获:
行锁变表锁的情况:
- 行锁是建立在索引字段的基础上,如果行锁定的列不是索引列则会升级为表锁。(行锁 锁的是索引!!!)
- 索引列数据重复过多情况下,会导致索引失效,行锁变表锁。(像是唯一索引和 主键索引 这种唯一性大的不会变成,但数据重复率多的会变成)
尽量避免操作非索引的字段
参考文章
https://www.jianshu.com/p/477b7ccba3d2
- 【教程】使用TensorFlow对象检测接口标注数据集
- [喵咪大数据]Hadoop单机模式
- 【死磕Java并发】—–Java内存模型之happens-before
- 9个,程序员又爱又恨的编程习惯
- Dubbo 源码解析 —— Cluster
- 【死磕Java并发】—–Java内存模型之从JMM角度分析DCL
- 基于PhalApi2的Redis拓展
- [喵咪BELK实战(3)] logstash+filebeat搭建
- Dubbo源码解析 —— Router
- 【死磕Java并发】—–深入分析volatile的实现原理
- phalcon-入门篇3(优美的URL与Config)
- 数据库中间件 Sharding-JDBC 源码分析 —— 事务(一)之BED
- 熔断器 Hystrix 源码解析 —— 命令执行(二)之执行隔离策略
- phalapi-入门篇4(国际化高可用和自动生成文档)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 通过 Trait 水平扩展 PHP 类功能
- 通过对象组合水平扩展 PHP 类功能
- DO,DTO,VO,POJO 你知道吗?
- Python 爬虫进阶必备 | AES-CBC 的 Pyhon 实现要怎么写?给代码就完事了
- Babel:下一代Javascript语法编译器
- 如何定位及优化SQL语句的性能问题
- Java线程安全如何进行原子操作,一致性的最佳实践
- 冒泡排序
- 现有CDP-DC集群启用Auto-TLS
- 打卡001/这是一篇软文
- 技术角 | 在CentOS 8上使用Elastic Stack: Elasticsearch/Kibana 7.8部署与认证配置
- 技术角 | 解决ES SQL命令行启动报错 ./x-pack-env: No such file or directory
- Linux常用命令归类总结
- 潜藏在PHP安全的边缘——浅谈PHP反序列化漏洞
- 对比MySQL,学会在Pandas中实现SQL的常用操作