MySQL事务分析和锁机制分析

  • 事务
    • 事务控制语句
    • 目的
    • 组成
    • 特征
  • 概念
    • redo日志
    • undo日志
    • MVCC多版本并发控制Multi version concurrency control
  • ACID特性
    • 原子性(A)
    • 持久性(D)
    • 一致性(C)
    • `隔离性(I)`
  • 隔离性的实现
    • 隔离级别
    • 锁类型
    • 共享锁(S)
    • 排他锁(X)Exclusive lock
    • 意向锁
    • 自增锁(AI)AUTO-INC Lock
  • 锁算法
    • 记录锁Record Lock
    • 间隙锁Gap Lock
    • 记录锁+间隙锁Next-Key Lock
    • 插入意向锁insert-intention lock
  • 锁的对象
  • 并发读异常
    • 脏读
    • `不可重复读`
    • 幻读
  • `丢失更新`
  • 隔离级别下并发读异常
  • 并发死锁
    • 相反顺序加锁,造成死锁
    • 锁冲突造成死锁
  • 查看死锁
  • 死锁解决
  • 如何避免死锁

事务

事务控制语句

-- 显示开启事务
START TRANSACTION | BEGIN
-- 提交事务
COMMIT
-- 回滚事务
ROLLBACK
-- 创建一个保存点,类似于C中的label
SAVEPOINT identifier
-- 删除一个保存点
RELEASE SAVEPOINT identifiter
-- 事务回滚到保存点
ROLLBACK TO [SAVEPOINT] identifier

目的

事务将数据库从一种一致性状态转换为另一种一致性状态

组成

事务可由一条非常简单的SQL语句组成,页可以由一组复杂的SQL语句组成

特征

  • 事务是访问和更新数据库的一个程序执行单元
  • 单条语句是隐含的事务
  • 多条语句需要主动开启事务
  • 通过设置set autocommit=0禁止事务自动提交,之后需要commit才能提交事务

概念

redo日志

redo日志用来实现事务的持久性,事务提交时,必须将该事务的所有日志写入到日子文件进行持久化

  • redo log顺序写,记录的是对每个页的修改
  • 只有发生宕机的时候,才会拿redo log进行恢复

undo日志

undo日志用来帮助事务回滚以及MVCC的功能,存储再共享表空间中

  • 实现rollback,记录事务每一步的具体操作,当rollback时,会执行相反的动作
  • 实现MVCC功能,记录行的版本信息

MVCC多版本并发控制Multi version concurrency control

  • 目的:用来实现一致性的非锁定读;非锁定读是指不需要等待,访问到行上读到加了X锁的行数据,就去读一个快照
  • 每一次事务提交都会产生一个快照,历史数据
  • 为什么读取快照数据不需要上锁?因为是由事务会对快照数据进行修改

ACID特性

原子性(A)

事务具有原子性,通过undo log来实现回滚操作

持久性(D)

把操作进行持久化,即使操作过程中宕机,通过redo log实现

一致性(C)

一致性指事务将数据库从一种一致性状态转换为下一种一致性状态,事务执行前后,数据库完整性约束没有被破坏,一个事务单元需要提交后才能够被其他事务可

  • 一致性由原子性、隔离性以及持久性共同来维护。

隔离性(I)

事务的隔离性要求每个读写事务的对象对其他事务的操作对象能相互分离,并发事务之间不会相互影响。

  • 设置不同的隔离级别,破坏一致性,能够提高性能。级别越高并发性能约低,级别越低并发性能越高
  • 通过MVCC和锁来实现
  • 表、页、行三种粒度加锁,操作哪在哪加锁

隔离性的实现

隔离级别

隔离级别针对的主要是读?
innodb默认隔离级别是可重复读repeatable read

  • read uncommitted读未提交
    读不加锁,写加排它锁
  • read committed读已提交
    支持MVCC,也就是提供一致性非锁定读
    读取操作读取历史快照的最新版本数据(最新提交的数据)
  • repeatable read可重复读
    支持MVCC
    读取操作读取事务开始时的版本数据
  • serializable串行化
    给读加了共享锁,所有事务都是串行化执行.

-- 设置隔离级别
SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 或者采用下面的方式设置隔离级别
SET @@tx_isolation='REPEATABLE READ';
SET @@global.tx_isolation = 'REPEATABLE READ';
transaction_isolation
-- 查看全局隔离级别
SELECT @@global.tx_isolation;
-- 查看当前会话隔离级别
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;
-- 手动加共享锁
SELECT ... LOCK IN SHARE MODE;
-- 手动加排它锁
SELECT ... FOR UPDATE;
-- 查看当前的锁信息
SELECT * FROM information_schema.innodb_locks;
-- 新版注意点
-- tx_isolation变为transaction_isolation
SELECT @@SESSION .transaction_isolation;
SELECT @@GLOBAL .transaction_isolation;
SELECT @@transaction_isolation;
-- nformation_schema.innodb_locks变为PERFORMANCE_SCHEMA .data_lock_waits;
SELECT * FROM PERFORMANCE_SCHEMA .data_locks;
SELECT * FROM PERFORMANCE_SCHEMA .data_lock_waits;

锁机制用于管理对共享资源的并发访问,用来实现事务的隔离级别。

锁类型

MySQL事务采用的是粒度锁,针对表(B+树)、页(B+树叶子节点)、行(B+树叶子节点中的某一行)三种粒度锁
共享锁和排它锁都是行级别锁;
意向共享锁和意向排它锁都是表级别的锁;

共享锁(S)

事务读操作加的锁,给一行加读锁
read uncommitted: 没有加共享锁,没有mvcc
read committed: 没有加共享锁,由mvcc,读最新提交版本
repeatable read: 没有加共享锁,有mvcc,读事务开始前的版本
serializable: 自动加共享锁

排他锁(X)Exclusive lock

事务删除或更新加的锁,对某一行加锁,事务提交或事务回滚后释放锁.

意向锁

意义: 表明了某个事务持有了锁或准备去持有锁
目的: 为了协调行锁和表锁的关系,支持多粒度(行锁和表锁)的锁并存.
例子: 事务A想修改table中的row数据,需要给row加上行级别的排它锁,同时会给table表加上意向排它锁;此时如果事务B想要修改table中的rowb数据,也需要给table加一个表级的意向排他锁,此时事务B就会被阻塞

  • 意向共享锁(IS)Intentional sharing lock
    事务在请求S锁前,需要先获得IS锁
  • 意向排他锁(IX)Intentional exclusive lock
    事务在请求X锁前,需要先获得IX锁

q1 为什么意向锁是表级锁呢?
当我们需要加一个排他锁时,需要根据意向锁去判断表中有没有数据行被锁定(行锁);
(1)如果意向锁是行锁,则需要遍历每一行数据去确认;
(2)如果意向锁是表锁,则只需要判断一次即可知道有没数据行被锁定,提升性能。

q2:意向锁怎么支持表锁和行锁并存?
(1)首先明确并存的概念是指数据库同时支持表、行锁,而不是任何情况都支持一个表中同时有一个事务A持有行锁、又有一个事务B持有表锁,因为表一旦被上了一个表级的写锁,肯定不能再上一个行级的锁。
(2)如果事务A对某一行上锁,其他事务就不可能修改这一行。这与“事务B锁住整个表就能修改表中的任意一行”形成了冲突。所以,没有意向锁的时候,让行锁与表锁共存,就会带来很多问题。于是有了意向锁的出现,如q1的答案中,数据库不需要在检查每一行数据是否有锁,而是直接判断一次意向锁是否存在即可,能提升很多性能

自增锁(AI)AUTO-INC Lock

是一种特殊的表级锁,发生在AUTO_INCREMENT约束下的插入操作,在完成对自增长插入的sql语句后立即释放。


S X IS IX AI
S 兼容 冲突 兼容 冲突 冲突
S 兼容 冲突 兼容 冲突 冲突
X 冲突 冲突 冲突 冲突 冲突
IS 兼容 冲突 兼容 兼容 兼容
IX 冲突 冲突 兼容 兼容 兼容
AI 冲突 冲突 兼容 兼容 冲突

  • innodb支持的是行级别的锁,mysim支持的是表级别的锁
  • 意向锁相互兼容,并不会阻塞除全表扫描外的任何请求
  • IS锁只对X锁冲突,或X锁与其他锁都冲突
  • 加S锁需要在所在表和行加意向锁IS,再在所在行加S锁
  • 加X锁需要在所在表和行加意向锁IX,再在所在行加X锁

锁算法

记录锁Record Lock

当个记录行的锁

间隙锁Gap Lock

全开区间,锁定一个范围,但不包含记录本身,Repeatable read级别以上支持
如果 REPEATABLE READ 修改 innodb_locks_unsafe_for_binlog = 0 ,那么隔离级别相当于退化为 READ COMMITTED;

记录锁+间隙锁Next-Key Lock

左开右闭区间,锁定一个范围,并锁住记录本身

插入意向锁insert-intention lock

insert操作时产生,在多事务同时写入不同数据至同一索引间隙的时候,并不需要等待其他事务完成,不会产生锁等待。
1-7 插入3和4,没有则只能加gap lock将1-7全锁住,这样子4就没办法插入了
插入意向锁能够使3和4同时插入

  • 提升间隙插入的并发性能
GAP(持有) Insert Intention(持有) Record(持有) Next-key(持有)
GAP(请求) 兼容 兼容 兼容 兼容
Insert Intention(请求) 冲突 兼容 兼容 冲突
Record(请求) 兼容 兼容 冲突 冲突
Next-key(请求) 兼容 兼容 冲突 冲突

分析死锁就是根据这个来的
死锁:再在请求insert intention但是已经被gap持有了

一个事务已经获取了插入意向锁,对其他事务是没有任何影响的;
一个事务想要获取插入意向锁,如果有其他事务已经加了 gap lock 或 Next-key lock 则会阻塞;
这个是重点,死锁之源;

锁的对象

重点考虑INNODB在read committed和repeatable read中的情况
无索引-全局扫描-表级别的锁
命中就是行锁,未命中就加gap锁
为什么没有命中会有间隙锁?避免幻读问题
可重复读加了一个gap锁
用优化器看是怎么索引的,再去分析锁

  • 对read commited和repeatable read,分别讨论以下的情况

    • 聚集索引,查询命中
    • 聚集索引,查询未命中
    • 辅助唯一索引,查询命中
    • 辅助唯一索引,查询未命中
    • 辅助非唯一索引,查询命中
    • 辅助非唯一索引,查询未命中
    • 无索引
    • 聚集索引,范围查询
    • 辅助索引,范围查询
    • 修改索引值

并发读异常

脏读

事务B比事务先运行,事务A读到事务B未提交的数据,读到修改的数据
解决方法:提升隔离级别>=read committed

seq session A session B
1 SET @@tx_isolation=‘READ UNCOMMITTED’; SET @@tx_isolation=‘READ UNCOMMITTED’;
2 BEGIN;
3 UPDATE account_t SET money = money - 100 WHERE name = ‘A’;
4 BEGIN;
5 SELECT money FROM account_t WHERE name = ‘A’;
6 SELECT money FROM account_t WHERE name = ‘B’;
7 UPDATE account_t SET money = money - 100 WHERE name = ‘B’;
8 COMMIT COMMIT

不可重复读

事务AB同时进行, 事务A对数据进行修改,事务A先提交, 事务B对数据进行查询,查到了事务A修改完的提交数据
解决方法:提升隔离级别>=repeatedable read

seq session A session B
1 SET @@tx_isolation=‘READ COMMITTED’; SET @@tx_isolation=‘READ COMMITTED’;
2 BEGIN; BEGIN;
3 SELECT money FROM account_t WHERE name = ‘A’;
4 UPDATE account_t SET money = money - 100 WHERE name = ‘A’;
5 COMMIT; SELECT money FROM account_t WHERE name = ‘A’;
6 COMMIT;

幻读

幻读是针对一个范围的数据。
幻读是两次读取同一个范围内的记录两次结果集不一样
结果集不一样:可能不同个数,也可能相同个数内容不一样

seq session A session B
1 SET @@tx_isolation=‘REPEATABLE READ’; SET @@tx_isolation=‘REPEATABLE READ’;
2 BEGIN; BEGIN;
3 SELECT * FROM account_t WHERE id >= 2;
4 INSERT INTO account_t(id,name,money) VALUES (4,‘D’,1000);
5 COMMIT; SELECT * FROM account_t WHERE id >= 2;
6 COMMIT;

丢失更新

两个事务都是写,提交覆盖和回滚覆盖
回滚覆盖在INNODB中不可能产生

seq session A session B
1 SET @@tx_isolation=‘REPEATABLE READ’; SET @@tx_isolation=‘REPEATABLE READ’;
2 BEGIN; BEGIN;
3 SELECT money FROM account_t WHERE name = ‘A’;
4 SELECT money FROM account_t WHERE name = ‘A’;
5 UPDATE account_t SET money = 1100 WHERE name = ‘A’;
6 COMMIT;
7 UPDATE account_t SET money = 900 WHERE name = ‘A’;
8 COMMIT;

隔离级别下并发读异常

隔离级别 回滚覆盖 脏读 不可重复读 幻读 提交覆盖
READ UNCOMMITTED 不存在 存在 存在 存在 存在
READ COMMITTED 不存在 不存在 存在 存在 存在
REPEATABLE READ 不存在 不存在 不存在 存在(手动加锁) 存在(手动加锁)
SERIALIZABLE 不存在 不存在 不存在 不存在 不存在

并发死锁

两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一种相互等待的现象。
MySQL中采用wait-fro-graph(等待图-采用非递归深度优化的图算法实现)的方式来进行死锁的检验;

相反顺序加锁,造成死锁

不同表的加锁顺序相反或相同表不同行的加锁顺序相反造成死锁。

锁冲突造成死锁

在innodb的repeatable read级别下,最常见的时插入意向锁和gap锁冲突造成死锁

查看死锁

-- 开启标准监控
CREATE TABLE innodb_monitor (a INT) ENGINE=INNODB;
-- 关闭标准监控
DROP TABLE innodb_monitor;
-- 开启锁监控
CREATE TABLE innodb_lock_monitor (a INT) ENGINE=INNODB;
-- 关闭锁监控
DROP TABLE innodb_lock_monitor-- 开启标准监控
set GLOBAL innodb_status_output=ON;
-- 关闭标准监控
set GLOBAL innodb_status_output=OFF;
-- 开启锁监控
set GLOBAL innodb_status_output_locks=ON;
-- 关闭锁监控
set GLOBAL innodb_status_output_locks=OFF;
-- 将死锁信息记录在错误日志中
set GLOBAL innodb_print_all_deadlocks=ON;-- 查看事务
select * from information_schema.INNODB_TRX;
-- 查看锁
select * from information_schema.INNODB_LOCKS;
-- 查看锁等待
select * from information_schema.INNODB_LOCK_WAITS;

死锁解决

  • 顺序相反型,调整执行顺序
  • 锁冲突型,更换语句或者降低隔离级别

如何避免死锁

尽可能以相同顺序来访问索引记录和表;
如果能确定幻读和不可重复读对应用影响不大,考虑将隔离级别降低为RC;
添加合理的索引,不走索引将会为每一行记录加锁,死锁概率非常大;
尽量在一个事务中锁定所需要的所有资源,减小死锁概率;
避免大事务,将大事务分拆成多个小事务;大事务占用资源多,耗时长,冲突概率变高;
避免同一时间点运行多个对同一表进行读写的概率;

MySQL事务分析和锁机制分析相关推荐

  1. OB锁机制分析和测试

    OB锁机制分析 OB锁机制:https://www.oceanbase.com/docs/community/observer-cn/V3.1.3/0000000000161645 ob的锁是行级锁, ...

  2. 深入浅出MySQL事务处理和锁机制

    深入浅出MySQL事务处理和锁机制 2015-01-13 架构师之旅 1. 事务处理和并发性 1.1. 基础知识和相关概念 1 )全部的表类型都可以使用锁,但是只有 InnoDB 和 BDB 才有内置 ...

  3. mysql innodb 的锁机制_Mysql之Innodb锁机制详解

    InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION):二是采用了行级锁.关于事务我们之前有专题介绍,这里就着重介绍下它的锁机制. 总的来说,InnoDB按照不同的分类共有 ...

  4. 【数据库】MySQL中的锁机制

    MySQL中的锁机制 数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则. MySQL 数据库由于其自身架构的特点,存在多种数据存储引擎,每种 ...

  5. 从一个死锁看mysql innodb的锁机制

    2019独角兽企业重金招聘Python工程师标准>>> 背景及现象 线上生产环境在某些时候经常性的出现数据库操作死锁,导致业务人员无法进行操作.经过DBA的分析,是某一张表的inse ...

  6. [转载] 数据库分析手记 —— InnoDB锁机制分析

    作者:倪煜 InnoDB锁机制常常困扰大家,不同的条件下往往表现出不同的锁竞争,在实际工作中经常要分析各种锁超时.死锁的问题.本文通过不同条件下的实验,利用InnoDB系统给出的各种信息,分析了锁的工 ...

  7. MySQL数据库:锁机制

    当数据库中多个事务并发存取同一数据的时候,若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性.MySQL锁机制的基本工作原理就是,事务在修改数据库之前,需要先获得相应的锁,获得锁的 ...

  8. Mysql InnoDB 的锁机制

    目录 前言 1. 锁的分类 1.1 实现方式 1.2 锁的粒度 2. 查询操作加锁方式 2.1 一致性非锁定读 2.2 一致性锁定读 3. 锁的算法 4. 锁的升级 5. 死锁 6.总结 前言 锁机制 ...

  9. MySQL中的锁机制详细说明

    一.MySQL锁机制起步 锁是计算机用以协调多个进程间并发访问同一共享资源的一种机制.MySQL中为了保证数据访问的一致性与有效性等功能,实现了锁机制,MySQL中的锁是在服务器层或者存储引擎层实现的 ...

最新文章

  1. MySQL This function has none of DETERMINISTIC, NO SQL...错误1418 的原因分析及解决方法
  2. yum 方式安装nginx
  3. Boost::context模块callcc的解析器测试程序
  4. 计算机应用技术 平面设计,全国信息化计算机应用技术水平教育考试试卷 平面设计师...
  5. [转载] Google Java代码规范
  6. 使用正则表达式实现将浮点数点左边的数每三位添加一个逗号
  7. verilog实现多周期处理器之——目录及总述
  8. 每日一题[LeetCode 689]三个无重叠子数组的最大和
  9. java技术英文名词读音_Java开发,Java development,音标,读音,翻译,英文例句,英语词典...
  10. 《考研公共课复习指导》数学篇1:考研数学策略
  11. AHU校赛网赛解题报告
  12. [TI TDA4 J721E] Sensor 鱼眼摄像头 LDC畸变校正模块LUT的创建和生成——详解
  13. ZYB's Biology
  14. Web 面试之 HTTP和浏览器
  15. 转贴:ubuntu 7.10 常用软件与编程环境搭建
  16. Ubuntu Edgy Sources list
  17. ESP32开发-LVGL显示图片
  18. android studio中的文本替换
  19. Linux就该这么19期高清录播-入门实战-企业常见服务搭建
  20. 在服务器上解压压缩文件,在服务器端实现文件自动压缩和解压

热门文章

  1. C#通过Windows API捕获窗,获取窗口文本(FindWindow、GetWindowText),附录:Windows窗口消息大全、Windows API大全
  2. 天龙八部采集-生活技能(矿石和药材)坐标位置
  3. 计算机信息技术基础...,计算机信息技术基础
  4. 无领导小组讨论应对技巧及经典案例
  5. linux微软雅黑字体库_linux 使用微软雅黑字体
  6. Spring 的控制反转/依赖注入
  7. vista常见故障及解决
  8. 更智能的云米双开门风冷冰箱,除了追剧,还能让食材井井有条
  9. CVPR2021|| Coordinate Attention注意力机制
  10. 前庭电刺激(GVS)的数据分析及在神经康复中的应用