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加锁分析的更多相关文章

  1. MySQL中一条SQL的加锁分析

    MySQL中一条SQL的加锁分析 id主键 + RC id唯一索引 + RC id非唯一索引 + RC id无索引 + RC id主键 + RR id唯一索引 + RR id非唯一索引 + RR id ...

  2. 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 ...

  3. 【MySql系列】MySql踩坑系列

    问题一:远程登录报错Host '192.168.181.201' is not allowed to connect to this MySQL server 解决: 问题二:MySql access ...

  4. Mysql系列二:Mysql 开发标准规范

    原文链接:http://www.cnblogs.com/liulei-LL/p/7729983.html 一.表设计 1. 库名.表名.字段名使用小写字母,“_”分割. 2. 库名.表名.字段名不超过 ...

  5. MySQL系列(二)--MySQL存储引擎

    影响数据库性能的因素: 1.硬件环境:CPU.内存.存盘IO.网卡流量等 2.存储引擎的选择 3.数据库参数配置(影响最大) 4.数据库结构设计和SQL语句 MySQL采用插件式存储引擎,可以自行选择 ...

  6. MySQL系列:MySQL的基本使用

    数据库的基本操作 在MySQL数据库中,对于一个MySQL示例,是可以包含多个数据库的. 在连接MySQL后,我们可以通过 show databases; 来进行查看有那么数据库.这里已经存在一些库了 ...

  7. MySQL 系列(四)主从复制、备份恢复方案生产环境实战

    第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 第三篇:MySQL 系列(三)你不知道的 视图.触发器.存储过程.函数 ...

  8. MySQL 系列(三)你不知道的 视图、触发器、存储过程、函数、事务、索引、语句

    第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 第三篇:MySQL 系列(三)你不知道的 视图.触发器.存储过程.函数 ...

  9. MySQL 系列(二) 你不知道的数据库操作

    第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 本章内容: 查看\创建\使用\删除 数据库 用户管理及授权实战 局域网 ...

  10. MySQL 系列(五) 多实例、高可用生产环境实战

    MySQL 系列(五) 多实例.高可用生产环境实战   第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 史上最屌.你不知道的数据库操作 第三 ...

随机推荐

  1. Ansible - [08] 模块应用

    firewalld 模块 使用firewalld模块可以配置防火墙策略 [root@control ~]# cat ~/ansible/firewall.yml --- - hosts: agent ...

  2. Java Map一些基本使用方法

    1 // Map key值不能相同,value值可以相同 2 // HashMap中的Entry对象是无序排列的 3 4 // 实例化1 5 Map<String, String> map ...

  3. ollama系列1:轻松3步本地部署deepseek,普通电脑可用

    本文主要介绍如何通过ollama快速部署deepseek.qwq.llama3.gemma3等大模型,网速好的小伙伴10分钟就能搞定.让你摆脱GPU焦虑,在普通电脑上面玩转大模型. 安装指南(无废话版 ...

  4. New Bing 全面开放?我看未必

    前段时间大家应该都被ChatGPT刷屏了,其实就回答来说New Bing 才是最厉害的,因为它底层使用了ChatGPT 并且可以支持联网查询数据,回答中还能支持看到出处,方便确认其真实性. New B ...

  5. linux ssh 免密登录

    1.服务器端开启密钥登录模式 $ vim /etc/ssh/sshd_config # 是否允许 root 远程登录 PermitRootLogin yes # 密码登录是否打开 PasswordAu ...

  6. go strings包

    //是否包含指定的字符串中任意一个字符 有一个出现过 就返回true fmt.Println(strings.ContainsAny(s1,"glass")) //返回指定字符出现 ...

  7. JOKER 低代码平台 20250313 重磅更新:全方位升级,解锁开发新体验

    JOKER 低代码平台于 2025 年 3 月 13 日迎来了一次全面且深度的升级.本次更新聚焦前端交互.服务端功能以及通用操作等多个关键领域,致力于打造更卓越的开发环境,为开发者们带来更加高效.稳定 ...

  8. halcon 入门教程(六) 图像匹配(基于形状的模板匹配)与缺陷检测区域定位

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/18783476 有兴趣可以多看其他的halcon教程 halcon 学习教程目录 本篇主要讲一下 ...

  9. Effective Java理解笔记系列-第2条-何时考虑用构建器?

    为什么写这系列博客? 在阅读<Effective Java>这本书时,我发现有许多地方需要仔细认真地慢慢阅读并且在必要时查阅相关资料才能彻底搞懂,相信有些读者在阅读此书时也有类似感受:同时 ...

  10. 【网络攻防】ARP欺骗实验

    实验概述 ARP欺骗是一类地址欺骗类病毒,属于木马病毒,自身不具备主动传播的特性,不会自我复制.但是由于其发作的时候会不断向全网发送伪造的ARP数据包,导致网络无法正常运行,严重的甚至可能带来整个网络 ...