MySQL事务原理详解,一篇文章让你搞懂
事务(ACID)
场景:小明向小强转账10元
原子性(Atomicity)
转账操作是一个不可分割的操作,要么转失败,要么转成功,不能存在中间的状态,也就是转了一半的这种情况。我们把这种要么全做,要么全不做的规则称之为原子性。
隔离性(lsolation)
另外一个场景:
- 小明向小强转账10元
- 小明向小红转账10元
隔离性表示上面两个操作是不能相互影响的
一致性(Consistency)
对于上面的转账场景,一致性表示每一次转账完成后,都需要保证整个系统的余额等于所有账户的收入减去所有账户的支出。
如果不遵循原子性,也就是如果小明向小强转账10元,但是只转了一半,小明账户少了10元,小强账户并没有增加,所以没有满足一致性了。
同样,如果不满足隔离性,也有可能导致破坏一致性。
所以说,数据库某些操作的原子性和隔离性都是保证一致性的一种手段,在操作执行完成后保证符合所有既定的约束则是一种结果。
实际上我们也可以对表建立约束来保证一致性。
持久性(Durability)
对于转账的交易记录,需要永久保存。
事务的概念
我们把需要保证原子性、隔离性、一致性和持久性的一个或多个数据库操作称之为一个事务。
事务的使用 开启事务
BEGIN语句代表开启一个事务,后边的单词WORK可有可无。开启事务后,就可以继续写若干条语句,这些语句
都属于刚刚开启的这个事务。
BEGIN[WORK]
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
mysql> sql...
START TRANSACTION
START TRANSACTION语句和BEGIN语句有着相同的功效,都标志着开启一个事务,比如这样:
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> sql...
提交事务
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)
mysql> UPDATE account SET balance = balance - 10 WHERE id = 1;
Query OK, 1 row affected (0.02 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> UPDATE account SET balance = balance + 10 WHERE id = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)
手动终止事务
> mysql> BEGIN; Query OK, 0 rows affected (0.00 sec) mysql> UPDATE
> account SET balance = balance - 10 WHERE id = 1; Query OK, 1 row
> affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql>
> UPDATE account SET balance = balance + 1 WHERE id = 2; Query OK, 1 row
> affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql>
> ROLLBACK; Query OK, 0 rows affected (0.00 sec)
这里需要强调一下,ROLLBACK语句是我们程序员手动的去回滚事务时才去使用的,如果事务在执行过程中遇到了某些错误而无法继续执行的话,事务自身会自动的回滚。
自动提交
mysql> SHOW VARIABLES LIKE 'autocommit';
默认情况下,如果我们不显式的使用START TRANSACTION或者BEGIN语句开启一个事务,那么每一条语句都算是一个独立的事务,这种特性称之为事务的自动提交
如果我们想关闭这种自动提交的功能,可以使用下边两种方法之一:
显式的的使用START TRANSACTION或者BEGIN语句开启一个事务。这样在本次事务提交或者回
滚前会暂时关闭掉自动提交的功能。
把系统变量autocommit的值设置为OFF,就像这样: SET autocommit = OFF; 这样的话,我们写入的多条语句就算是属于同一个事务了,直到我们显式的写出COMMIT语句来把这个事务提交掉,或者显式的写出ROLLBACK语句来把这个事务回滚掉
隐式提交
当我们使用START TRANSACTION或者BEGIN语句开启了一个事务,或者把系统变量autocommit的值设置为OFF时,事务就不会进行自动提交,但是如果我们输入了某些语句之后就会悄悄的提交掉,就像我们输入了COMMIT语句了一样,这种因为某些特殊的语句而导致事务提交的情况称为隐式提交,这些会导致事务隐式提交的语句包括:
- 定义或修改数据库对象的数据定义语言(Data definition language,缩写为:DDL)。所谓的数据
库对象,指的就是数据库、表、视图、存储过程等等这些东西。当我们使用CREATE、ALTER、
DROP等语句去修改这些所谓的数据库对象时,就会隐式的提交前边语句所属于的事务。 - 隐式使用或修改mysql数据库中的表:当我们使用ALTER USER、CREATE USER、DROP USER、
GRANT、RENAME USER、SET PASSWORD等语句时也会隐式的提交前边语句所属于的事务。 - 事务控制或关于锁定的语句:当我们在一个事务还没提交或者回滚时就又使用START
TRANSACTION或者BEGIN语句开启了另一个事务时,会隐式的提交上一个事务。或者当前的autocommit系统变量的值为OFF,我们手动把它调为ON时,也会隐式的提交前边语句所属的事务。或者使用LOCKTABLES、UNLOCKTABLES等关于锁定的语句也会隐式的提交前边语句所属 的事务。 - 加载数据的语句:比如我们使用LOAD DATA语句来批量往数据库中导入数据时,也会隐式的提交前边语句所属的事务。
- 其它的一些语句:使用ANALYZE TABLE、CACHE INDEX、CHECK TABLE、FLUSH、 LOAD INDEX INTO CACHE、OPTIMIZE TABLE、REPAIR TABLE、RESET等语句也会隐式的提交前边语 句所属的事务。
保存点
如果你开启了一个事务,并且已经敲了很多语句,忽然发现上一条语句有点问题,你只好使用ROLLBACK语句来让数据库状态恢复到事务执行之前的样子,然后一切从头再来,总有一种一夜回到解放前的感觉。所以MYSQL提出了一个保存点(英文:savepoint)的概念,就是在事务对应的数据库语句中打几个点,我们在调用ROLLBACK语句时可以指定会滚到哪个点,而不是回到最初的原点。定义保存点的语法如下:
SAVEPOINT 保存点名称;
当我们想回滚到某个保存点时,可以使用下边这个语句(下边语句中的单词WORK和SAVEPOINT是可有可无的):
ROLLBACK [WORK] TO [SAVEPOINT]保存点名称;
不过如果ROLLBACK语句后边不跟随保存点名称的话,会直接回滚到事务执行之前的状态。
如果我们想删除某个保存点,可以使用这个语句:
RELEASE SAVEPOINT保存点名称;
隔离性详解
--修改隔离级别
mysql> set session transaction isolation level read uncommitted;
--查看隔离级别
mysql> select @@tx_isolation;
读已提交(READ UNCOMMITTED)
一个事务可以读到其他事务还没有提交的数据,会出现脏读。
一个事务读到了另一个未提交事务修改过的数据,这就是脏读。
读未提交(READ COMMITTED)
一个事务只能读到另一个已经提交的事务修改过的数据,并且其他事务每对该数据进行一次修改并提交后,该事务都能查询得到最新值,会出现不可重复读、幻读。
如果一个事务先根据某些条件查询出一些记录,之后另一个事务又向表中插入了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另一个事务插入的记录也读出来,这就是幻读。
可重复读(REPEATABLEREAD)
一个事务第一次读过某条记录后,即使其他事务修改了该记录的值并且提交,该事务之后再读该条记录时,读到的仍是第一次读到的值,而不是每次都读到不同的数据,这就是可重复读,这种隔离级别解决了不可重复,但是还是会出现幻读。
串行化(SERIALIZABLE)
以上3种隔离级别都允许对同一条记录同时进行读-读、读-写、写-读的并发操作,如果我们不允许读-写、写-读
的并发操作,可以使用SERIALIZABLE隔离级别,这种隔离基金因为对同一条记录的操作都是串行的,所以不会
出现脏读、幻读等现象。
总结
READ UNCOMMITTED隔离级别下,可能发生脏读脏读、不可重复读、、幻读问题。
READCOMMITTED隔离级别下,可能发生不可重复读 不可重复读和幻读问题,但是不会发生 问题,但是不会发生脏读问题。
REPEATABLE READ隔离级别下,可能发生幻读幻读问题,不会发生脏读脏读和不可重复读的题。
SERIALIZABLE隔离级别下,各种问题都不可以发生。
注意:这四种隔离级别是SQL的标准定义,不同的数据库会有不同的实现,特别需要注意的是MySQL在在REPEATABLE READ隔离级别下,是可以禁止幻读问题的发生的 隔离级别下,是可以禁止幻读问题的发生的。
版本链
对于使用InnoDB存储引擎的表来说,它的聚簇索引记录中都包含两个必要的隐藏列(row_id并不是必要的,我们创建的表中有主键或者非NULL唯一键时都不会包含row_id列):
trx_id:每次对某条记录进行改动时,都会把对应的事务id赋值给trx_id隐藏列。
roll_pointer:每次对某条记录进行改动时,这个隐藏列会存一个指针,可以通过这个指针找到该记 录修改前的信息。
Readview
对于使用READ UNCOMMITTED隔离级别的事务来说,直接读取记录的最新版本就好了,对于使用
SERIALIZABLE隔离级别的事务来说,使用加锁的方式来访问记录。对于使用READ COMMITTED和
REPEATABLE READ隔离级别的事务来说,就需要用到我们上边所说的版本链了,核心问题就是:需要判断一下版本链中的哪个版本是当前事务可见的。
ReadView中主要包含4个比较重要的内容:
- m_ids:表示在生成ReadView时当前系统中活跃的读写事务的事务id列表。
- min_trx_id:表示在生成ReadView时当前系统中活跃的读写事务中最小的事务id,也就是m_ids中的最小值。
- max_trx_id:表示生成ReadView时系统中应该分配给下一个事务的id值。
- creator_trx_id:表示生成该ReadView的事务的事务id。
注意max_trx_id并不是m_ids中的最大值,事务id是递增分配的。比方说现在有id为1,2,3这三个事务,之
后id为3的事务提交了。那么一个新的读事务在生成ReadView时,m_ids就包括1和2,min_trx_id的值就是1,
max_trx_id的值就是4。
有了这个ReadView,这样在访问某条记录时,只需要按照下边的步骤判断记录的某个版本是否可见:
如果被访问版本的trx_id属性值与ReadView中的creator_trx_id值相同,意味着当前事务在访问它自
己修改过的记录,所以该版本可以被当前事务访问。如果被访问版本的trx_id属性值小于ReadView中的min_trx_id值,表明生成该版本的事务在当前事
务生成ReadView前已经提交,所以该版本可以被当前事务访问。如果被访问版本的trx_id属性值大于ReadView中的max_trx_id值,表明生成该版本的事务在当前事
务生成ReadView后才开启,所以该版本不可以被当前事务访问。如果被访问版本的trx_id属性值在ReadView的min_trx_id和max_trx_id之间,那就需要判断一下
trx_id属性值是不是在m_ids列表中,如果在,说明创建ReadView时生成该版本的事务还是活跃
的,该版本不可以被访问;如果不在,说明创建ReadView时生成该版本的事务已经被提交,该版 本可以被访问
READ COMMITTED的实现方式
每次读取数据前都生成一个ReadView
REPEATABLE READ的实现方式
在第一次读取数据时生成一个ReadView
MVCC总结
MVCC(Multi-Version Concurrency Control ,多版本并发控制)指的就是在使用READ COMMITTD、
REPEATABLE READ这两种隔离级别的事务在执行普通的SEELCT操作时访问记录的版本链的过程。可以使不同事务的读-写、写-读操作并发执行,从而提升系统性能。READ COMMITTD、REPEATABLE READ这两个隔离级别的一个很大不同就是:生成ReadView的时机不同,READ COMMITTD在每一次进行普通SELECT操作前都会生成一个ReadView,而REPEATABLE READ只在第一次进行普通SELECT操作前生成一个ReadView,之后的查询操作都重复使用这个ReadView就好了。
至此MySQL事务就给大家讲完了,了解更多JAVA知识及资料可关注微信公众号“老周扯IT”
MySQL事务原理详解,一篇文章让你搞懂相关推荐
- mysql 事务原理详解
前言 事务是mysql Innodb引擎的一大特点,可以说,在日常开发中,对于mysql事务的使用无处不在,因此深入了解并掌握mysql的事务原理很有必要. 一.mysql事务简介 事务 是一组操作集 ...
- Mysql事务原理详解
事物 目的 事务将数据库从一种一致性状态转换为另一种一致性状态: 组成 事务可由一条非常简单的SQL语句组成,也可以由一组复杂的SQL语句组成: Innodb支持事务,Myisam是不支持事务的.这个 ...
- MySQL索引原理详解
MySQL索引原理详解 索引的本质 索引的分类 Hash 索引 二叉树 B树(二三树) B+树 主键目录 索引页 索引页的分层 非主键索引 回表 索引的本质 索引的本质是一种排好序的数据结构. 索引的 ...
- 一篇文章带你搞懂网络层(网际层)-- 地址篇
网络层(Network Layer)是OSI模型中的第三层(TCP/IP模型中的网际层),提供路由和寻址的功能,使两终端系统能够互连且决定最佳路径,并具有一定的拥塞控制和流量控制的能力.相当于发送邮件 ...
- Spring事务原理详解
一.使用 spring事务开启和使用比较简单,需要有数据源和事务管理器,然后在启动门面类上开启事务,在需要使用事务的地方添加注解就可以了,我们简单做一下回顾. 1.配置数据源 spring.datas ...
- 玩转Mysql系列 - 第22篇:mysql索引原理详解
Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 欢迎大家加我微信itsoku一起交流java.算法.数据库相关技术. 这是Mysql系列第22篇. 背景 使用mys ...
- 【图文动画详解原理系列】1.MySQL 索引原理详解
MySQL简介 MySQL是一个开放源代码的关系数据库管理系统.原开发者为瑞典的MySQL AB公司,最早是在2001年MySQL3.23进入到管理员的视野并在之后获得广泛的应用.2008年MySQL ...
- MySQL事务——万字详解
目录 前言 一.事务的概念 1.1 什么是事务 1.2 事务的属性 1.3 事务的版本支持 1.4 事务提交方式 1.5 事务的常见操作 1.5.1 准备阶段: 1.5.2 手动演示回滚操作 1.5. ...
- mysql mvcc 原理详解
前言 很多人在谈起mysql事务的时候都能很快的答出mysql的几种事务隔离级别,以及在各自隔离级别下产生的问题,但是一旦谈到为什么会产生这样的结果时会觉得难以回答,说到底,还是对底层的原理未做深入的 ...
最新文章
- UNICODE 码和字符的相互转换
- IR2104s半桥驱动使用经验
- 基于matlab的单相pwm逆变电路的仿真研究,基于MATLAB的单相PWM逆变电路的仿真研究...
- apache 二级域名设置
- mysql update实质,UPDATE注射(mysql+php)的两个模式
- 自动化脚本上传图片怎么办_一切都自动化后我们将怎么办?
- PyTorch系列入门到精通——autograd与逻辑回归
- scala中的if esle使用
- 在Java中如何高效判断数组中是否包含某个元素
- CSDN上传自己的资源赚积分教程
- Tensorflow搭建GAN网络
- 关卡 - Aragami关卡设计
- stemming与lemmatization
- Excel--查找、替换及定位
- Obsidian看板指北
- Qt焦点事件 setFocusPolicy
- 【数据分析与挖掘(一)】笔试题汇总(附答案)
- Numpy 怎么把arange ()产生的列表 变成一个行向量或者列向量
- Linux下c++/c使用getsockopt()的记录
- Googleearth提取数字高程等高线
热门文章
- 【阿里笔试题】线程篇
- Verilog基础语法--运算符【常用的几种】
- python中什么函数表示求绝对值_python绝对值怎么计算
- 2021年上半年软件设计师上午真题及答案解析(三)
- 2022广航蓝桥杯选拔赛压轴题:取数博弈游戏
- Python 练习实例03:一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?
- 科技爱好者周刊(第 219 期):如何防止帐号被黑
- STM32_光敏、温湿度传感的选择?
- 博南石上海公司的那个hr,貌似叫什么harvey hou,太恶心了。。。
- C++实现K-means,聚类原理解析(并用在图片像素点聚类)