MySQL 事务原理分析

事务

  • 前提:有并发连接。
  • 定义:事务是用户定义的一系列操作,这些操作要么都做,要么都不做,是一个不可分割的单位。
  • 目的:事务将数据库从一种一致性状态转换为另一种一致性状态,保证系统始终处于一个完整且正确的状态。
  • 组成:事务可由一条非常简单的 SQL 语句组成,也可以由一组复杂的SQL 语句组成。
  • 特征:
    • 在数据库提交事务时,可以确保要么所有修改都已经保存,要么所有修改都不保存。
    • 事务是访问并更新数据库各种数据项的一个程序执行单元。
    • 在 MySQL innodb 下,单条 SQL 语句都具备事务,可以通过 set autocommit = 0,设置当前会话手动提交事务。
  • 事务控制语句
    -- 开启事务
    START TRANSACTION | BEGIN
    -- 提交事务,并使得已对数据库做的所有修改持久化
    COMMIT
    -- 回滚事务,结束用户的事务,并撤销正在进行的所有未提交的修改
    ROLLBACK
    -- 创建一个保存点,一个事务可以有多个保存点
    SAVEPOINT identifier
    -- 删除一个保存点
    RELEASE SAVEPOINT identifier
    -- 事务回滚到保存点
    ROLLBACK TO [SAVEPOINT] identifier
    

ACID 特性

  • 原子性(A)
    • 事务操作要么都做(提交),要么都不做(回滚),事务是访问并更新数据库各种数据项的一个程序执行单元,是一个不可分割的单位。
    • 通过 undo log 来实现回滚操作,undo log 记录事务的 DML 操作,当回滚时,回放事务 DML 操作的逆运算。
    • 在 MVCC 中,undo log 记录事务 DML 操作提交后产生的行数据版本信息。
  • 一致性(C)
    • 一致性指事务将数据库从一种一致性状态转变为下一种一致性的状态,在事务执行前后,数据库完整性约束没有被破坏。
      • 例如:一个表的姓名有唯一约束,如果一个事务对姓名进行修改,但是在事务提交或事务回滚后,表中的姓名变得不唯一了,这样就破坏了一致性。
    • 逻辑上的一致性是可以被破坏的。(设置不同程度的隔离级别适当地破坏逻辑上的一致性)
    • 一致性由原子性、隔离性以及持久性共同来维护。
  • 隔离性(I)
    • 隔离性表示各个事务之间相互影响的程度。
    • 目的:防止多个并发事务交叉执行导致数据不一致。
    • 通过设置不同程度的隔离级别,适当地破环逻辑上的一致性,从而提高性能。
    • 通过 MVCC 和 锁来实现。
      • MVCC:多版本并发控制,它不使用锁来限制读操作,从而实现高效并发读性能。
      • 锁用来处理并发 DML 操作,数据库中提供粒度锁的策略,针对表(聚簇索引 B+ 树)、页(聚簇索引 B+ 树叶子节点)、行(叶子节点当中某一段记录行)三种粒度加锁。
  • 持久性(D)
    • 事务一旦完成,要将数据所做的变更记录下来,包括数据存储和多副本的网络备份。
    • 事务提交后,事务 DML 操作将会持久化(写入 redo log 磁盘文件:哪一个页、页偏移值、具体数据),即使发生宕机等故障,数据库也能将数据恢复。 redo log 记录的是物理日志,确保内存数据的安全

隔离级别

  • 目的:提升 MySQL 并发处理 SQL 语句的性能。
  • ISO 和 ANIS SQL 标准制定了四种事务隔离级别的标准,MySQL innodb 默认支持的隔离级别是 repeatable read。
  • read uncommitted(读未提交)
    • 读操作不做任何处理。
    • 写操作加 X 锁,写锁在事务提交或回滚后释放。
  • read committed(读已提交)(RC)
    • 读操作使用 MVCC,读取最新版本的行数据。
    • 写操作加 X 锁。
  • repeatable read(可重复读)(RR)
    • 读操作使用 MVCC,读取事务开始前版本的行数据。
    • 写操作加 X 锁。
  • serializable(可串行化)
    • 读操作加 S 锁,所以事务都是串行化执行,此时隔离级别最严苛。
    • 写操作加 X 锁。
-- 设置隔离级别
SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 或者采用下面的方式设置隔离级别
SET @@tx_isolation = 'REPEATABLE READ';
SET @@global.tx_isolation = 'REPEATABLE READ';
-- 查看全局隔离级别
SELECT @@global.tx_isolation;
-- 查看当前会话隔离级别
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;

-- 手动给读操作加 S 锁
SELECT ... LOCK IN SHARE MODE;
-- 手动给读操作加 X 锁
SELECT ... FOR UPDATE;
-- 查看当前锁信息
SELECT * FROM information_schema.innodb_locks;

不同隔离级别并发异常

  • 脏读
    • 事务 A 读到事务 B 未提交的数据,也就是事务 A 读到脏数据。
seqsession Asession B
1SET @@tx_isolation=‘READ UNCOMMITTED’;SET @@tx_isolation=‘READ UNCOMMITTED’;
2BEGIN;
3             UPDATE account_t SET money = money - 100 WHERE name = ‘A’;
4BEGIN;
5SELECT money FROM account_t WHERE name = ‘A’;
6COMMITCOMMIT
  • 不可重复读
    • 一个事务内两次读取同一个数据不一样
    • 一般而言,不可重复读的问题是可以接受的,因为读到已经提交的数据,一般不会带来很大的问题,所以很多厂商(如 Oracle、SQL Server)默认隔离级别就是 read committed。
seqsession Asession B
1SET @@tx_isolation=‘READ COMMITTED’;SET @@tx_isolation=‘READ COMMITTED’;
2BEGIN;BEGIN;
3SELECT money FROM account_t WHERE name = ‘A’;
4                UPDATE account_t SET money = money - 100 WHERE name = ‘A’;
5COMMIT;
6SELECT money FROM account_t WHERE name = ‘A’;
6COMMIT;
  • 幻读
    • 一个事务内两次读取同一个范围内的记录得到的结果集不一样快照读和当前读不一致
    • 在 repeatable read 隔离级别下通过读加锁解决。
seqsession Asession B
1SET @@tx_isolation=‘REPEATABLE READ’;SET @@tx_isolation=‘REPEATABLE READ’;
2BEGIN;BEGIN;
3SELECT * FROM account_t WHERE id >= 2;                
4INSERT INTO account_t(id,name,money) VALUES (4,‘D’,1000);
5COMMIT;
6INSERT INTO account_t(id,name,money) VALUES (4,‘D’,1000); # 报错,因为幻读
seqsession Asession B
1SET @@tx_isolation=‘REPEATABLE READ’;SET @@tx_isolation=‘REPEATABLE READ’;
2BEGIN;BEGIN;
3SELECT * FROM account_t WHERE id >= 2 lock in share mode;
4                INSERT INTO account_t(id,name,money) VALUES (4,‘D’,1000); # 等待执行
5INSERT INTO account_t(id,name,money) VALUES (4,‘D’,1000);# 等待执行
6COMMIT;# 报错,因为破坏了数据库完整性约束

MVCC

  • MVCC 是一致性非锁定读,也就是读不加锁。
  • 每一次开启事务的时候,MySQL 都会为其创建一个唯一的事务 id(长度为 64 位,并且一直递增)。
  • read view
    • m_ids:创建 read view 时,已启动但未提交的事务 id 列表。
    • min_trx_id:创建 read view 时,已启动但未提交的最小事务 id。
    • max_trx_id:创建 read view 时,预分配给下一个未开启事务的 id。
    • creator_trx_id:创建该 read view 的事务 id。
  • 聚簇索引记录的隐藏列
    • trx_id
      • 事务修改记录时,trx_id 记录该修改事务 id。
    • roll_pointer
      • 事务修改记录时,将旧记录写入 undo log,该指针指向旧版本记录。

在这里插入图片描述

  • 事务可见性问题
    • 事务可以看到事务本身的修改。
    • 事务间的可见性
      • trx_id < min_trx_id:已提交,可见。
      • trx_id >= max_trx_id:未启动,不可见。
      • min_trx_id <= trx_id < max_trx_id
        • trx_id in m_ids:已启动但未提交,不可见。
        • trx_id not in m_ids:已提交,可见。
  • 读已提交
    • 每次读取数据时,生成新的 read view。
  • 可重复读
    • 启动事务时,生成新的 read view,一直使用直到事务提交。
  • 快照读
    select * from table where
  • 当前读
    select * from table where ? lock in share mode # S 锁(读锁)
    select * from table where ? for update         # X 锁(写锁)
    
    insert into table values(...)
    update table set ? where ?
    delete from table where ?
    

  • 全局锁
    • 用于全库备份。
flush tables with read lock  # 整个数据库处于只读状态
unlock tables 
  • 表级锁
    • 表锁
      lock tables 'table' [read/write]
      unlock tables
      
    • 元数据锁
      crud
      alter
      
    • 意向锁
      • 目的:告诉其他事务,此时该表正在被一个事务访问。
      • 作用:阻塞表级读写锁(全面扫描加锁),由于 innodb 支持的是行级别的锁,意向锁并不会阻塞除了全表扫描以外的任何请求。
      • 意向锁存储在表结构中。
      • 意向锁之间是互相兼容的,并且由数据库自动添加。
      • 当事务试图读或写某一条记录时,会先在表上加上意向锁,然后才在要操作的记录上加上读锁或写锁。这样判断表中是否有记录加锁就很简单了,只要看下表上是否有意向锁就可以了。
      • 分类
        • 意向共享锁(IS):对一张表中某几行加的共享锁。
        • 意向排他锁(IX):对一张表中某几行加的排他锁。
    • auto-inc 锁
      • 特殊表锁,实现自增约束,语句结束后释放锁(而非在事务结束时释放)。
  • 行级锁
    • 记录锁(record lock)
      • 共享锁(S)
        • 事务读操作加的锁,对某一行加锁。
        • 在 serializable 隔离级别下,默认给读操作加共享锁。
        • 在 RR 隔离级别下,需手动加共享锁,可解决幻读问题。
        • 在 RC 隔离级别下,没必要加共享锁,采用的是 MVCC。
        • 在 read uncommitted 隔离级别下,既没有加锁也没有使用 MVCC。
      • 排他锁(X)
        • 事务删除或更新加的锁,对某一行加锁。
        • 在 4 种隔离级别下,都添加了排他锁,事务提交或事务回滚后释放锁。
    • 间隙锁(gap lock)
      • RR 隔离级别下,where 条件语句未命中时会自动添加间隙锁。
      • 防止其他事务在记录间隙插入新的记录,从而避免幻读现象。
      • 间隙锁会锁定一个范围,加锁区间为 (row1, row2)。
    • 临键锁(next-key lock)
      • 记录锁 + 间隙锁。
      • 加锁区间为 (row1, row2]。
  • 查询
    • MVCC:undo log 实现历史版本记录。
    • S 锁:lock in share mode
    • X 锁:for update
    • 不做任何处理:read uncommitted 使用的策略。
  • 删除、更新
    • 自动添加 X 锁。
  • 插入
    • 使用插入意向锁(特殊的 gap 锁)和 X 锁。
      • 在多事务同时写入不同数据至同一索引间隙的时候,并不需要等待其他事务完成,不会发生锁等待。
    • auto-inc lock:特殊表锁实现。

锁兼容

GAP(持有)Insert Intention(持有)Record(持有)Next-key(持有)
GAP(请求)兼容兼容兼容兼容
Insert Intention(请求)冲突兼容兼容冲突
Record(请求)兼容兼容冲突冲突
Next-key(请求)兼容兼容冲突冲突
  • 横向:表示已经持有的锁。
  • 纵向:表示正在请求的锁。
  • 一个事务已经获取了插入意向锁,对其他事务是没有任何影响的。
  • 一个事务想要获取插入意向锁,如果有其他事务已经加了 gap lock 或 next-key lock 则会阻塞,这个是重点,死锁之源。

锁的对象

  • 行级锁是针对表的索引加锁,索引包括聚簇索引和辅助索引。
  • 表级锁是针对页或表进行加锁;
  • 重点考虑 innodb 在 read committed 和 repeatable read 隔离级别下锁的情况。
  • 聚簇索引,查询命中:
    UPDATE students SET score = 100 WHERE id = 15;
    

在这里插入图片描述

  • 聚簇索引,查询未命中:
     UPDATE students SET score = 100 WHERE id = 16;
    

在这里插入图片描述

  • 辅助唯一索引,查询命中:
    UPDATE students SET score = 100 WHERE no = 'S0003';
    

在这里插入图片描述

  • 辅助唯一索引,查询未命中:
     UPDATE students SET score = 100 WHERE no = 'S0008';
    

在这里插入图片描述

  • 辅助非唯一索引,查询命中:
    UPDATE students SET score = 100 WHERE name = 'Tom';
    

在这里插入图片描述

  • 辅助非唯一索引,查询未命中:
     UPDATE students SET score = 100 WHERE name = 'John';
    

在这里插入图片描述

  • 无索引:
    UPDATE students SET score = 100 WHERE score = 22;
    

在这里插入图片描述

  • 聚簇索引,范围查询:
    UPDATE students SET score = 100 WHERE id <= 20;
    

在这里插入图片描述

  • 辅助索引,范围查询:
    UPDATE students SET score = 100 WHERE age <= 23;
    

在这里插入图片描述

  • 修改索引值:
    UPDATE students SET name = 'John' WHERE id = 15;
    

在这里插入图片描述


死锁

  • 死锁原因:并发事务在执行过程中,因争夺锁资源而造成的一种互相等待的现象。
  • 相反加锁顺序死锁
    • 不同表加锁顺序相反。
    • 相同表不同行加锁顺序相反。
      • 给辅助索引行加锁的时候,同时会给聚簇索引行加锁。
      • 使用外键索引时,给父表加锁,同时隐含给子表加锁。
    • 解决:调整加锁顺序。
  • 锁冲突死锁
    • RR 隔离级别下,插入意向锁与 gap 锁冲突死锁。一个事务想要获取插入意向锁,如
      果有其他事务已经加了 gap lock 或 next-key lock 则会阻塞。
    • 解决:降低隔离级别至 RC。
  • 如何避免死锁
    • 尽可能以相同顺序来访问索引记录和表。
    • 如果能确定幻读和不可重复读对应用影响不大,考虑将隔离级别降低为 RC。
    • 添加合理的索引,不走索引将会为每一行记录加锁,死锁概率非常大。
    • 尽量在一个事务中锁定所需要的所有资源,减小死锁概率。
    • 避免大事务,将大事务分拆成多个小事务,大事务占用资源多,耗时长,冲突概率变高。
    • 避免同一时间点运行多个对同一表进行读写的概率。
  • 查看死锁
    • 系统表
      -- 开启标准监控
      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;
      

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/414825.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】从链表到LinkedList类

&#x1f9e7;&#x1f9e7;&#x1f9e7;&#x1f9e7;&#x1f9e7;个人主页&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388; &#x1f9e7;&#x1f9e7;&#x1f9e7;&#x1f9e7;&#x1f9e7;数据结构专栏&#x1f388;&#x1f388;&#x1f388;&…

NerfStudio安装及第一个场景重建

NerfStudio文档是写在windows和linux上安装&#xff0c;本文记录Linux安装的过程&#xff0c;且我的cuda是11.7 创建环境 conda create --name nerfstudio -y python3.8 conda activate nerfstudio python -m pip install --upgrade pip Pytorch要求2.0.1之后的,文档推荐cud…

JavaWeb——005 请求响应 分层解耦(Postman、三层架构、IOC、DI、注解)

SpringBootWeb请求响应 这里写目录标题 SpringBootWeb请求响应前言1. 请求1.1 Postman1.1.1 介绍1.1.2 安装 1.2 简单参数1.2.1 原始方式1.2.2 SpringBoot方式1.2.3 参数名不一致 1.3 实体参数1.3.1 简单实体对象1.3.2 复杂实体对象 1.4 数组集合参数1.4.1 数组1.4.2 集合 1.5 …

产品老化试验目的、用途

什么是老化试验&#xff1f; 老化试验是通过模拟产品在使用过程中的老化情况&#xff0c;来评估产品在长期使用后的性能和可靠性。这种测试可以帮助制造商了解产品的寿命和耐久性&#xff0c;以及产品在不同环境条件下的表现。 模拟量采集/老化房采集软件 为什么需要进行老化试…

【Leetcode每日一刷】贪心算法01:455.分发饼干、376. 摆动序列、53. 最大子序和

博主简介&#xff1a;努力学习和进步中的的22级计科生博主主页&#xff1a; Yaoyao2024每日一句: “ 路虽远&#xff0c;行则将至。事虽难&#xff0c;做则可成。” 文章目录 前言&#xff1a;贪心算法一、455.分发饼干二、376. 摆动序列三、53. 最大子序和 前言&#xff1a;贪…

挑战杯 基于机器视觉的图像拼接算法

前言 图像拼接在实际的应用场景很广&#xff0c;比如无人机航拍&#xff0c;遥感图像等等&#xff0c;图像拼接是进一步做图像理解基础步骤&#xff0c;拼接效果的好坏直接影响接下来的工作&#xff0c;所以一个好的图像拼接算法非常重要。 再举一个身边的例子吧&#xff0c;…

信号系统之切比雪夫过滤器

1 切比雪夫和巴特沃斯的响应 切比雪夫响应是一种数学策略&#xff0c;通过允许频率响应中的纹波来实现更快的滚降。使用这种方法的模拟和数字滤波器称为切比雪夫滤波器。这些滤波器因使用切比雪夫多项式而得名&#xff0c;切比雪夫多项式由俄罗斯数学家帕夫努蒂切比雪夫&#…

基于FPGA的9/7整数小波变换和逆变换verilog实现,包含testbench

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 9/7整数小波变换原理 4.2 逆变换过程 5.算法完整程序工程 1.算法运行效果图预览 将测试结果导入到matlab显示 2.算法运行软件版本 vivado2019.2&#xff0c;matlab2022a 3.部分核心程…

寒假作业Day 01

这个项目主要是为了复习博主之前关于C语言和数据结构的寒假作业&#xff0c;大家也可以根据这些题目自己进行填写并检查自己的知识点是否过关 博主也会有错误&#xff0c;所以如果大家看到错误&#xff0c;也希望大家能够进行指正&#xff0c;谢谢大家&#xff01; Day 01 一…

静态链表(1)

什么叫静态链表&#xff1f;——用顺序表模拟链表&#xff0c;就叫做静态链表 第一列相当于数据域data&#xff0c;第二列相当于指针域next&#xff0c; 第一行&#xff08;0&#xff09;相当于头结点&#xff08;头结点的数据域不放数据&#xff09; &#xff08;a&#xff…

Rocky Linux安装部署Elasticsearch(ELK日志服务器)

一、Elasticsearch的简介 Elasticsearch是一个强大的开源搜索和分析引擎&#xff0c;可用于实时处理和查询大量数据。它具有高性能、可扩展性和分布式特性&#xff0c;支持全文搜索、聚合分析、地理空间搜索等功能&#xff0c;是构建实时应用和大规模数据分析平台的首选工具。 …

【C语言】while循环语句

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;C语言 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进步&…

flask知识--01

flask介绍 # python 界的web框架&#xff1a; Django&#xff1a;大而全&#xff0c;使用率较高 &#xff1a;https://github.com/django/django -FastAPI&#xff1a;新项目选择使用它&#xff1a;https://github.com/tiangolo/fastapi -flask&#xff1a;公司一些…

【论文阅读】深度学习在过冷沸腾气泡动力学分割中的应用

Application of deep learning for segmentation of bubble dynamics in subcooled boiling 深度学习在过冷沸腾气泡动力学分割中的应用 期刊信息&#xff1a;International Journal of Multiphase Flow 2023 级别&#xff1a;EI检索 SCI升级版工程技术2区 SCI基础版工程技术3区…

探讨:围绕 props 阐述 React 通信

在 ✓ &#x1f1e8;&#x1f1f3; 开篇&#xff1a;通过 state 阐述 React 渲染 中&#xff0c;以 setInterval 为例&#xff0c;梳理了 React 渲染的相关内容。 &#x1f4e2; 本篇会 ✓ &#x1f1e8;&#x1f1f3; 围绕 props 阐述 React 通信 props React 组件使用 pro…

7.1 嵌入式软件设计资源管理-引言

1、简介 实时和嵌入式系统的一个显著特点是对有限资源的管理。这些资源可能是CPU时间、内存、网络带宽等&#xff0c;它们的有限性要求系统设计者必须精心管理以确保系统的高效运行。 1.1 资源管理 资源管理是实时和嵌入式系统设计中的一个核心问题&#xff0c;涉及CPU时间、…

三、软件-系统架构设计师笔记-计算机系统基础知识

计算机系统概述 计算机系统是指用于数据管理的计算机硬件、软件及网络组成的系统。 它是按人的要求接收和存储信息&#xff0c;自动进行数据处理和计算&#xff0c;并输出结果信息的机器系统。 冯诺依曼体系计算机结构&#xff1a; 1、计算机硬件组成 冯诺依曼计算机结构将…

kafka三节点集群平滑升级过程指导

一、前言 Apache Kafka作为常用的开源分布式流媒体平台&#xff0c;可以实时发布、订阅、存储和处理数据流,多用于作为消息队列获取实时数据&#xff0c;构建对数据流的变化进行实时反应的应用程序&#xff0c;已被数千家公司用于高性能数据管道、流分析、数据集成和任务关键型…

Keepalived双机热备——Haproxy搭建web群集

一、认识keepalived keepalived是一个开源的软件&#xff0c;用于实现高可用性和负载均衡。它主要用于在多个服务器之间提供故障转移和负载均衡的功能。keepalived可以监控服务器的状态&#xff0c;并在主服务器发生故障时自动将备份服务器切换为主服务器&#xff0c;以确保服…

统计分析笔记3

文章目录 统计检验选择正确的统计检验统计检验是做什么的&#xff1f;何时进行统计检验选择参数化测试&#xff1a;回归、比较或相关性选择非参数检验 假设检验的假设条件skewness什么是零偏度right skewleft skew计算skewnesswhat to do if your data is skewed kurtosis怎么计…