Mysql(三)事务原理及分析
简介
定义:事务的本质是并发控制的单元,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。
事务的前提:并发连接访问;
组成:事务可由一条非常简单的 SQL 语句组成,也可以由一组复杂的 SQL 语句组成;MySQL innodb 下,单条语句都具备事务;可以通过 autocommit = 0; 设置当前会话手动提交;
事务的生命周期:
- begin … commit
- begin … rollback
事务控制语句
-- 显示开启事务
START TRANSACTION | BEGIN
-- 提交事务,并使得已对数据库做的所有修改持久化
COMMIT
-- 回滚事务,结束用户的事务,并撤销正在进行的所有未提交的修改
ROLLBACK
-- 创建一个保存点,一个事务可以有多个保存点
SAVEPOINT identifier
-- 删除一个保存点
RELEASE SAVEPOINT identifier
-- 事务回滚到保存点
ROLLBACK TO [SAVEPOINT] identifier
ACID特性
原子性(A)
事务操作要么都做(提交),要么都不做(回滚);事务是访问并更新数据库各种数据项的一个程序执行单元,是不可分割的工作单位;通过 undolog 来实现回滚操作。undolog 记录的是事务每步具体操作,当回滚时,回放事务具体操作的逆运算;
事务包含的全部操作是一个不可分割的整体,要么全部执行,要么全部不执行;
虽然说事务要保持原子性,例如完整的串行执行就可以保证事务中指令执行的原子性;但是这种方式的性能是非常低的,因此Mysql通常会通过事务与事务之间指令的交叉执行来提高性能。
隔离性(I)
描述:各个事务之间互相影响的程度;防止多个并发事务交叉执行导致的数据不一致,通过锁和MVCC实现。
目的:主要规定多个事务访问同一数据资源,各个事务对该数据资源访问的行为,不同的隔离性是应对不同的现象(脏读、不可重复读、幻读);
事务的隔离性要求每个读写事务的对象对其他事务的操作对象能相互分离,并发事务之间不会相互影响,设定了不同程度的隔离级别,通过适度破环一致性,得以提高性能;通过 MVCC 和 锁来实现;MVCC 是多版本并发控制,主要解决一致性非锁定读,通过记录和获取行版本,而不是使用锁来限制读操作,从而实现高效并发读性能。锁用来处理并发 DML 操作;数据库中提供粒度锁的策略,针对表(聚集索引 B+ 树)、页(聚集索引 B+ 树叶子节点)、行(叶子节点当中某一段记录行)三种粒度加锁;
持久性(D)
事务一旦完成,要将数据所做的变更记录下来,包括数据存储和多副本的网络备份;
事务提交后,事务 DML 操作将会持久化(写入 redolog 磁盘文件 哪一个页 页偏移值 具体数据);即使发生宕机等故障,数据库也能将数据恢复。redolog 记录的是物理日志;
一致性(C)
事务的前后,所有的数据都保持一个一致的状态,不能违反数据的一致性检测(完整性约束检查);
一致性指事务将数据库从一种一致性状态转变为下一种一致性的状态,在事务执行前后,数据库完整性约束没有被破坏;一个事务单元需要提交之后才会被其他事务可见。例如:一个表的姓名是唯一键,如果一个事务对姓名进行修改,但是在事务提交或事务回滚后,表中的姓名变得不唯一了,这样就破坏了一致性;一致性由原子性、隔离性以及持久性共同来维护的。
隔离级别
ISO 和 ANIS SQL 标准制定了四种事务隔离级别的标准,隔离级别越高,性能越低。各数据库厂商在正确性和性能之间做了妥协,并没有严格遵循这些标准;MySQL innodb默认支持的隔离级别是 REPEATABLE READ;
READ UNCOMMITTED
读未提交;该级别下读操作不加锁,写操作加排他锁,写锁在事务提交或回滚后释放锁;会产生脏读。
READ COMMITTED
读已提交(RC);从该级别后支持 MVCC (多版本并发控制),也就是提供一致性非锁定读;该隔离级别下读取历史版本的最新数据,所以读取的是已提交的数据;会产生不可重复读的现象。
REPEATABLE READ
可重复读(RR);该级别下也支持 MVCC,此时读取操作读取事务开始时的版本数据;会产生幻读的现象。可以用当前读,即给读加锁来解决幻读现象。
-- 手动给读加 S 锁
SELECT ... LOCK IN SHARE MODE;
-- 手动给读加 X 锁
SELECT ... FOR UPDATE;
SERIALIZABLE
可串行化;该级别下给读加了共享锁;所以事务都是串行化的执行;此时隔离级别最严苛;
不同的隔离级别产生的不同的结果:
脏读:一个事务读到另一个未提交事务修改的数据;
不可重复读:一个事务两次读取同一个数据不一样;
幻读:一个事务内两次读到同一范围内的记录得到的结果集不一样;
锁
锁机制用于管理对共享资源的并发访问;用来实现事务的隔离级别 ;
锁类型
MySQL当中事务采用的是粒度锁;针对表(B+树)、页(B+树叶子节点)、行(B+树叶子节点当中某一段记录行)三种粒度加锁;粒度更小,并发性更好.
- 基于锁的属性分类:共享锁、排他锁。
- 基于锁的粒度分类:表锁、行锁(记录锁、间隙锁、临键锁)。
- 基于锁的状态分类:意向共享锁、意向排它锁。
属性锁
共享锁(S)
事务读操作加的锁;对某一行加锁;
在 SERIALIZABLE 隔离级别下,默认帮读操作加共享锁;
在 REPEATABLE READ 隔离级别下,需手动加共享锁,可解决幻读问题;
在 READ COMMITTED 隔离级别下,没必要加共享锁,采用的是 MVCC;
在 READ UNCOMMITTED 隔离级别下,既没有加锁也没有使用 MVCC;
排他锁(X)
事务删除或更新加的锁;对某一行加锁;
在4种隔离级别下,都添加了排他锁,事务提交或事务回滚后释放锁;
意向锁
当一个事务试图对整个表进行加锁(共享锁或排它锁)之前,首先需要获得对应类型的意向锁(意向共享锁或意向排他锁)。不然的话加锁时需要判断是否有其他事务获得了该表的锁,需要对每个索引节点遍历,费事。
意向共享锁(IS)
对一张表中某几行加的共享锁;
意向排他锁(IX)
对一张表中某几行加的排他锁;
目的:为了告诉其他事务,此时这条表被一个事务在访问;
作用:排除表级别读写锁 (全面扫描加锁);
行锁
Gap Lock
间隙锁,锁定一个范围,但不包含记录本身;全开区间;REPEATABLE READ 级别及以上支持间隙锁;
如果 REPEATABLE READ 修改 innodb_locks_unsafe_for_binlog = 0,那么隔离级别相当于退化为 READ COMMITTED;
Next-Key Lock
记录锁+间隙锁的组合,锁定一个范围,并且锁住记录本身;左开右闭区间;
Insert Intention Lock
插入意向锁,insert 操作的时候产生;在多事务同时写入不同数据至同一索引间隙的时候,并不需要等待其他事务完成,不会发生锁等待。
假设有一个记录索引包含键值 4 和 7,两个不同的事务分别插入 5 和 6,每个事务都会产生一个加在 4-7 之间的插入意向锁,获取在插入行上的排它锁,但是不会被互相锁住,因为数据行并不冲突。
MVCC
多版本并发控制;用来实现一致性的非锁定读;非锁定读是指不需要等待访问的行上X锁的释放;
在 read committed 和 repeatable read 下,innodb 使用 MVCC;然后对于快照数据的定义不同;在 read committed 隔离级别下,对于快照数据总是读取被锁定行的最新一份快照数据;而在 repeatable read 隔离级别下,对于快照数据总是读取事务开始时的行数据版本;
思考:为什么读取快照数据不需要上锁?
因为没有事务需要对历史的数据进行修改操作;
read view
在 read committed 和 read repeatable 隔离级别下,MVCC 采用 read view 来实现的,它们的区别在于创建 read view 时机不同:
read committed 隔离级别会在事务中每个 select 都会生成一个新的 read view,也意味着在同一个事务多次读取同一条数据可能出现数据不一致;因为在多次读取期间可能有其他事务修改了该条记录,并提交了;
read repeatable 隔离级别是启动事务时生成一个 read view,在整个事务读取数据都才使用这个 read view,这样保证了在事务期间读到的数据都是事务启动前的记录;
构成
m_ids:创建 read view 时,当前数据库活跃事务(开启未提交的事务)的事务 id 列表;
min_trx_id:创建 read view 时, m_ids 中的最小事务 id;
max_trx_id:创建 read view 时,当前数据库将为下一个事务分配的事务 id;并不一定是 m_ids 中的最大事务 id;
creator_trx_id:创建 read view 所在事务的 id;
聚集索引隐藏列
_row_id:没定义索引,没有非唯一索引时,会产生隐藏列_row_id
trx_id:当某个事务对某条聚集索引记录进行修改时,将会把当前事务的 id 赋值给 trx_id;
roll_pointer:当某个事务对某条聚集索引记录进行修改时,会将上一个版本的记录写到 undo log,然后通过roll_pointer 指向旧版本记录,通过它可以找到修改前的记录;
事务的可见性判断
trx_id < min_trx_id;说明该记录在创建 read_view 之前已经提交,所以对当前事务可见;
trx_id >= max_trx_id;说明该记录是在创建 read_view 之后启动事务生成的,所以对当前事务不可见;
min_trx_id <= trx_id < max_trx_id;此时需要判断是否在 m_ids 列表中:
- 在列表中;生成该版本记录的事务仍处于活跃状态,该版本记录对当前事务不可见;
- 不在列表中;生成该版本记录的事务已经提交,该版本记录对当前事务可见;
redo
redo 日志用来实现事务的持久性;内存中包含 redo log buffer,磁盘中包含 redo log file;
当事务提交时,必须先将该事务的所有日志写入到重做日志文件进行持久化,待事务的commit 操作完成才完成了事务的提交;
redo log 顺序写,记录的是对每个页的修改(页、页偏移量、以及修改的内容);在数据库运行时不需要对 redo log 的文件进行读取操作;只有发生宕机的时候,才会拿redo log 进行恢复;
undo
undo 日志用来帮助事务回滚以及 MVCC 的功能;存储在共享表空间中;undo 是逻辑日志,回滚时将数据库逻辑地恢复到原来的样子,根据 undo log 的记录,做之前的逆运算;比如事务中有 insert 操作,那么执行 delete 操作;对于 update 操作执行相反的 update 操作;
同时 undo 日志记录行的版本信息,用于处理 MVCC 功能;
并发读异常
脏读
事务(A)可以读到另外一个事务(B)中未提交的数据;也就是事务A读到脏数据;在读写分离的场景下,可以将 slave 节点设置为 READ UNCOMMITTED;此时脏读不影响,在 slave 上查询并不需要特别精准的返回值。
不可重复读
事务(A) 可以读到另外一个事务(B)中提交的数据;通常发生在一个事务中两次读到的数据是不一样的情况;不可重复读在隔离级别 READ COMMITTED 存在。一般而言,不可重复读的问题是可以接受的,因为读到已经提交的数据,一般不会带来很大的问题,所以很多厂商(如Oracle、SQL Server)默认隔离级别就是 READ COMMITTED;
幻读
两次读取同一个范围内的记录得到的结果集不一样;例如:以 name 为唯一键的表,一个事务中查询 select * from t where name = ‘mark’; 不存在,接下来 insert into t(name) values (‘mark’); 出现错误,因为此时另外一个事务也执行了 insert 操作;幻读在隔离级别 REPEATABLE READ 及以下存在;但是可以在 REPEATABLE READ 级别下通过读加锁(使用 next-key locking)解决;
解决:
区别
脏读和不可重复读的区别在于,脏读是读取了另一个事务未提交的数据,而不可重复读是读取了另一个事务提交之后的修改;本质上都是其他事务的修改影响了本事务的读取;
不可重复读和幻读比较类似;不可重复读是两次读取同一条记录,得到不一样的结果;而幻读是两次读取同一个范围内的记录得到的结果集不一样(可能不同个数,也可能相同个数内容不一样,比如x一行后又添加新行);不可重复读是因为其他事务进行了 update 操作,幻读是因为其他事务进行了 insert或者 delete 操作。
脏读、不可重复读、幻读都是一个事务写,一个事务读,由于一个事务的写导致另一个事务读到了不该读的数据;丢失更新是两个事务都是写;丢失更新分为提交覆盖和回滚覆盖;回滚覆盖数据库拒绝不可能产生,重点关注提交覆盖;
并发死锁
相反加锁顺序死锁
不同表的加锁顺序相反或者相同表不同行加锁顺序相反造成死锁;其中相同表不同行加锁顺序相反造成死锁有很多变种,其中容易忽略的是给辅助索引行加锁的时候,同时会给聚集索引行加锁;同时还可能出现在外键索引时,给父表加锁,同时隐含给子表加锁;触发器同样如此,这些都需要视情况分析;
解决:需要调整加锁顺序。
锁冲突死锁
innodb 在 RR 隔离级别下,最常见的是插入意向锁与 gap 锁冲突造成死锁;主要原理为:一个事务想要获取插入意向锁,如果有其他事务已经加了 gap lock 或 Next-key lock 则会阻塞;
死锁解决
对于顺序相反型,调整执行顺序;
对于锁冲突型,更换语句或者降低隔离级别;
如何避免死锁
尽可能以相同顺序来访问索引记录和表;
如果能确定幻读和不可重复读对应用影响不大,考虑将隔离级别降低为 RC;
添加合理的索引,不走索引将会为每一行记录加锁,死锁概率非常大;
尽量在一个事务中锁定所需要的所有资源,减小死锁概率;
避免大事务,将大事务分拆成多个小事务;大事务占用资源多,耗时长,冲突概率变高;
避免同一时间点运行多个对同一表进行读写的概率;
文章参考与<零声教育>的C/C++linux服务器高级架构系统教程学习
Mysql(三)事务原理及分析相关推荐
- MySQL笔记-死锁原理与分析及InnoDB中如何减少死锁
根据InnoDB的加锁规则(Record Lock.Gap Lock.meta data lock)可以写出不会发生死锁的SQL语句,也能定位出产生死锁的原因. 死锁产生的原因: 产生回路:两个或两个 ...
- 框架学习之Hibernate 第十节 事务原理与分析
1.事务 两种事务: ① JDBC事务:单个数据库的事务 一个SesisonFactory对应一个数据库,使用 JDBC 实现 常用代码的模板: Session session = null;Tran ...
- Spring的事务原理分析、与mysql的事务关系
spring事务?mysql事务? 系统中到底谁的事务是在保证数据的一致性,两个事务有什么关系? spring事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,s ...
- mysql 事务原理详解
前言 事务是mysql Innodb引擎的一大特点,可以说,在日常开发中,对于mysql事务的使用无处不在,因此深入了解并掌握mysql的事务原理很有必要. 一.mysql事务简介 事务 是一组操作集 ...
- Spring事务原理详解
一.使用 spring事务开启和使用比较简单,需要有数据源和事务管理器,然后在启动门面类上开启事务,在需要使用事务的地方添加注解就可以了,我们简单做一下回顾. 1.配置数据源 spring.datas ...
- Mysql分布式事务
Mysql分布式事务 XA协议 分布式事务模型 流程 两阶段提交 Mysql中的XA语法 使用演示 XA状态转换图 XA的BUG XA的性能问题 总结 参考资源 XA协议 为了规范分布式事务的管理,X ...
- MySQL事务原理分析(ACID特性、隔离级别、锁、MVCC、并发读异常、并发死锁以及如何避免死锁)
MySQL事务原理分析(ACID特性.隔离级别.锁.MVCC.并发读异常.并发死锁以及如何避免死锁) 一.事务 目的 组成 特征 事务空间语句 二.ACID特性 原子性(A) 隔离性(I) 持久性(d ...
- Linux服务器开发【有用知识】—MySQL事务原理分析
前言 今天的目标是学习MySQL事务原理分析,但是却似乎总是非常不顺利,概念和实操实在多到令人发指,故干脆轻松学完一节课,等到时机到了再重新刷一遍吧! 一.事务是什么? 将数据库从一致性状态转化成另一 ...
- 数据库之mysql事务原理分析与锁机制 详解
1.事务 1.2.目的 事务将数据库从一种一致性状态转换为另一种一致性状态: 1.3.组成 事务可由一条非常简单的SQL语句组成,也可以由一组复杂的SQL语句组成: 其中单条语句会默认自动添加事务控制 ...
最新文章
- python中文字符画、编写程序合理选取中文字符构造_编写程序,合理选取中文字符构造字符表,生成中文字符画。...
- Virtualization基础
- 几行简单代码实现DIV层上显示Tooltip效果
- [蓝桥杯]带分数-dfs
- java 1.5.0 gcj_CentOS安装JAVA后JAVA版本不对的问题
- php escapeshellcmd,利用/绕过 PHP escapeshellarg/escapeshellcmd函数
- 《21天学通C#》使用.NET数据类型定义变量
- iconfont-矢量图标字体的运用
- Pokémon Go呼应设计:让全世界玩家疯狂沉迷
- [数据库课程设计]基于Sql Server的教室信息管理系统(附部分源码)
- nginx搭建ftp文件服务器,nginx搭建ftp文件服务器
- eMTC是什么技术?
- [Spark中移动平均法的实现]
- 人人网(cookie登录)
- Unexpected exception encountered during query.解决办法
- zmud中的ansi颜色使用
- div做表格 html5,div+css制作表格
- 不一定是黑客,也可以是守护神《运用Python成为顶级黑客》
- 2014暑假ACM13级一批集训内容
- 如何将数据从旧PC传输到新Mac
热门文章
- PilotEdit(文本编辑器软件)官方中文版V14.5.0 | pilotedit是什么软件
- poi导出复杂的excle,简单易懂一看既会
- 【tio-core】1、tio-study是学习t-io的第一步
- 致诸弟·劝弟谨记进德修业
- Ubuntu16.04安装TensorFlow(GeForce Titan显卡)出现的问题记录
- Windows系统win10系统日历日程管理软件推荐
- OPPO R9st怎么刷机 OPPO R9st的刷机教程 OPPO R9st完美解除账号锁
- 【GPT4】微软 GPT-4 测试报告(9)结论与展望
- 基于Thinkphp5+phpQuery 网络爬虫抓取数据接口,统一输出接口数据api
- 常用队列系统设计,通用his就诊叫号抢号模式,通用his体检叫号自动分配模式...