1-2 【包子mysql系列】, 对mysql的innoDB加锁分析
innoDB的事务,是基于锁来实现的,用到事务不自然就会用到锁,而如果对锁理解的不通透,很容易造成线上问题。
数据库加锁的分析,和事务的引擎,隔离级别,索引,主键索引都有关系,
如果去考虑引擎和各种隔离级别的话,就会很复杂了,所以下面都是基于innoDB和RR的隔离级别进行分析:
表结构:

内容:

1 , 根据主键更新
如果根据主键来行数
|
事务A |
事务B |
|
|
update user set name='ce1' where id='1'; |
update user set name='ce3' where Id='3'; |
同时执行,都成功 |
|
update user set name='ce1' where id='1'; |
update user set name='ce3' where userId='10003'; |
B更新失败,直至:Lock wait timeout |
结论,如果根据非主键来更新,会把整个表进行锁定,无法 进行更新操作。
注:只要是根据主键索引来更新,哪怕事务A没命中主键,也不会锁定整个表
2,根据非索引非主键更新
|
事务A |
事务B |
|
|
update user set name='ce1' where userId='10001'; |
update user set name='ce3' where Id='3'; 或者 update user set name='ce3' where userId='10003' |
都会失败,如果非索引,直接锁表 |
3, 如果在userId 列上加入普通唯一索引
修改成

再更新
|
事务A |
事务B |
|
|
update user set name='ce1' where userId='10001'; |
update user set name='ce3' where Id='3'; 或者 update user set name='ce3' where userId='10003' |
都会成功,如果有唯一索引,也是能成功行数,互相不影响 |
4, 如果在userId 列上加入普通非唯一索引 (重点探讨)
把userId改成非唯一索引:

记录内容如下:
+----+--------+------+
| id | userId | name |
+----+--------+------+
| 1 | 10001 | ce1 |
| 2 | 10002 | ce2 |
| 3 | 10001 | ce3 |
| 4 | 10004 | ce4 |
+----+--------+------+
再相同操作
|
事务A |
事务B |
|
|
update user set name='ce1' where userId='10001'; |
update user set name='ce3' where Id='3'; |
B失误执行失败,显然id=3的这行也被锁住了 |
其实最终还是按主键锁住的记录 id=1和id=3的记录
非唯一索引与普通索引,更一步的区别是GAP锁
gap锁是用于解决幻读的存在,演示
把记录修改成,如:

id为pk. userId为Normal key
|
A事务 |
B事务 |
结果 |
|
begin; update user set name='ce22' where userId='100020'; |
||
|
insert into user (userId,name) values('100021','tttt'); |
直至事务失败超时 |
1, 首先GAP锁针对的是insert操作
2, 当更新userId='100020'时,会锁住两边的记录区间,防止幻读的存在。
3, 锁是作用在普通索引上,但由于索引是由B+树存储,那么锁住的是两边的区间,防止insert
GAP锁为什么不是锁住一条记录,而是锁住一个区间呢?
附上疑问: https://www.oschina.net/question/867417_2289606
其实:
GAP锁是解决幻读存在的,如当 delete时就必须锁住区间了
|
A事务 |
B事务 |
|
|
begin; delete from user where userId='888888'; |
||
|
insert into user (userId,name) values('100021','tttt'); |
OK, 可以插入 |
|
|
insert into user (userId,name) values('100041','tttt'); |
插入超时 |
可见,这个GAP锁,锁住的是100040~无穷大 的记录
死锁的产生分析:
1, 两条语句产生的死锁
id = pk, userId= key
最简单的。两条语句互相更新等待
|
begin; update user set name='ce1' where userId='100010'; |
begin; update user set name='ce2' where userId='100020'; |
|
update user set name='ce2' where userId='100020'; |
update user set name='ce1' where userId='100010'; |
|
最简单的死锁 |
2, 由于gap锁,删除一台不存在的记录
如,先删除一条记录,然后插入一条记录, 如果记录GAP锁冲突,两个事务容易互为死锁。如:
|
A事务 |
B事务 |
|
begin; delete from user where userId='100020'; (Query OK, 1 row affected) |
begin; |
|
delete from user where userId='565656'; |
|
|
insert into user (userId,name) values('100041','tttt'); |
|
|
insert into user (userId,name) values('100019','tttt'); |
结果直接抛出:
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
分析:
A事务 delete 加入gap锁【100010,100020】, 第二段【100020,100030】
B事务 delete加入gap 锁【100040,无穷大】
然后A事务插入,获取插入意向锁时B事务的GAP锁被阻塞
B事务插入,获取插入意向锁时时被A事务的GAP锁阻塞
结果死锁
1-2 【包子mysql系列】, 对mysql的innoDB加锁分析的更多相关文章
- MySQL中一条SQL的加锁分析
MySQL中一条SQL的加锁分析 id主键 + RC id唯一索引 + RC id非唯一索引 + RC id无索引 + RC id主键 + RR id唯一索引 + RR id非唯一索引 + RR id ...
- mysql InnoDB加锁分析
文章转载自:http://www.fanyilun.me/2017/04/20/MySQL%E5%8A%A0%E9%94%81%E5%88%86%E6%9E%90/ 以下实验数据基于MySQL 5.7 ...
- 【MySql系列】MySql踩坑系列
问题一:远程登录报错Host '192.168.181.201' is not allowed to connect to this MySQL server 解决: 问题二:MySql access ...
- Mysql系列二:Mysql 开发标准规范
原文链接:http://www.cnblogs.com/liulei-LL/p/7729983.html 一.表设计 1. 库名.表名.字段名使用小写字母,“_”分割. 2. 库名.表名.字段名不超过 ...
- MySQL系列(二)--MySQL存储引擎
影响数据库性能的因素: 1.硬件环境:CPU.内存.存盘IO.网卡流量等 2.存储引擎的选择 3.数据库参数配置(影响最大) 4.数据库结构设计和SQL语句 MySQL采用插件式存储引擎,可以自行选择 ...
- MySQL系列:MySQL的基本使用
数据库的基本操作 在MySQL数据库中,对于一个MySQL示例,是可以包含多个数据库的. 在连接MySQL后,我们可以通过 show databases; 来进行查看有那么数据库.这里已经存在一些库了 ...
- MySQL 系列(四)主从复制、备份恢复方案生产环境实战
第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 第三篇:MySQL 系列(三)你不知道的 视图.触发器.存储过程.函数 ...
- MySQL 系列(三)你不知道的 视图、触发器、存储过程、函数、事务、索引、语句
第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 第三篇:MySQL 系列(三)你不知道的 视图.触发器.存储过程.函数 ...
- MySQL 系列(二) 你不知道的数据库操作
第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 本章内容: 查看\创建\使用\删除 数据库 用户管理及授权实战 局域网 ...
- MySQL 系列(五) 多实例、高可用生产环境实战
MySQL 系列(五) 多实例.高可用生产环境实战 第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 史上最屌.你不知道的数据库操作 第三 ...
随机推荐
- 「二」移动光标、vim进入与退出、文本编辑之删除、插入、添加、编辑、光标移动、撤销
移动光标 h:向左移动 j:向下移动 k:向上移动 l:向右移动 vim进入与退出 按鍵, 确保处于正常模式 輸入:q! <回车>(丢弃所做的任何改动) 文本编辑之删除 在正常模式下修改命 ...
- vue生命周期调用
<template> <div> <!-- 用户页的面包屑导航 --> <nav aria-label="breadcrumb"> ...
- 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本地AI Agent
一.天价邀请码VS开源革命:打工人今夜无眠 昨夜科技圈被两个关键词刷屏:Manus激活码炒至5万元5,7,GitHub神秘项目OpenManus突然开源6,7.这场戏剧性对决的背后,是一场关于「A ...
- Vue2框架-基础
1. vue简介 什么是vue? Vue是一套用于构建用户界面的渐进式JavaScript框架.与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用.Vue 的核心库只关注视图层,方便与第三方 ...
- docker build 镜像时,无法访问网络
前言 在使用 docker build 命令构建 Docker 镜像时遇到无法联网的情况,可能会有多种情况的发生. 检查主机网络设置 检查你的主机是否配置了代理服务器或防火墙,这可能会阻止 Docke ...
- 使用PowerPoint优雅地更改证件照底色
使用PowerPoint优雅地更改证件照底色 首先我们打开一张空白的演示文稿,并将要修改的证件照进行粘贴.(图片来自窝窝摄影,侵删) 选中图片,点击 格式,再点击 删除背景. 点击标记要保留的区域,对 ...
- 【Python】使用PyInstaller把代码打包成exe可执行文件
使用PyInstaller打包自己写好的代码 零.需求 最近接到一个小单,需要批量修改文档内容,用Python做好后要打包成exe程序给客户的Win7电脑使用,此时需要用到PyInstaller打包自 ...
- 【Win32】VC6 Visual C/C++ 6.0 修改程序图标
零.需求 就想给自己的C程序加个图标,好看些 一.解决 1.操作步骤 1.新建一个资源脚本 2.在新建的脚本上右键,选择插入 3.选择Icon,点新建或者引入,如果你没有准备图标点新建,有的话直接点引 ...
- Oracle 11G R2 安装图解
个人学习需要,在Windows Server 2008 R2 上安装 Oracle 11G R2 Tips:需要下载2个文件,file1和file2 解压后需要合并到同一个文件夹下才能正常安装(这里就 ...
- Win10禁用UWP
Win10禁用UWP, HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\WindowsStore DisableStoreApps REG_DWORD 0 ...