MySQL中事务和事务的隔离级别
本文主要是帮助理解相关知识,没有具体的操作和代码。
事务
事务就是一组操作,这组操作要么全部成功,要么全部失败。
最经典的例子就是银行转账:
张三给李四转账100,对用户来说,就是一个操作。但对应到数据库中,至少需要三步:
//检查张三账户余额是否大于等于100
//张三账户-100
//李四账户+100
这三个操作可以没有顺序,但是必须全部成功或者全部失败。否则就可能导致张三损失100李四没收到,或者李四收到100但是张三没扣款成功(银行损失100)。
MySQL默认引擎InnoDB,支持事务;MyISAM引擎不支持事务。
事务的特性
前面说的其实都是事务的概念,具体怎么实现或者有什么要求呢?
一个运行良好的事务处理系统,必须基本满足四个特性(ACID),即原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)。
原子性(atomicity)
一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作。(这个特性基本上等同于事务的定义,所以必须满足)。
一致性(consistency)
数据库总是从一个一致性的状态转换到另外一个一致性的状态。在转账的例子中,若转账成功,张三和李四的账户总额和转账前也是一致。
隔离性(isolation)
一般来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。(这是本文的讨论的主要内容,因为在实际情况下,并不一定能保证隔离性。)
持久性(durability)
一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。
事务的隔离级别
事务间的隔离
事务的四个特性中,原子性,一致性,持久性多数情况下都能保证。稍微复杂的是隔离性,因为我们在学习的过程中很多时候都是单用户,单连接,也就是一个事务执行完成再去执行另一个,很难体会到隔离性的内涵。
不妨想一下春运时候的12306系统,每个用户要完成的操作:
//假设某一线路总票数100张
//1.查询余票
//2.买票即总票数-1
//3.付款
这三个操作组成一个事务,在高并发的情况下,一个用户甲执行到第二步,票数减到99,此时第二个用户乙查询余票,票数应该是100还是99 ?
针对类似的疑问,SQL规范提出了四种情形,或者说用四种级别实现了不同的需求,不同级别决定了用户乙看到的是100还是99。
这四种级别分别是:
READ UNCOMMITTED(未提交读)
在READ UNCOMMITTED级别,事务中的修改,即使没有提交,对其他事务也都是可见的。
回到前面的例子,如果设置为这个级别,用户乙看到的将是99。这导致的问题是如果甲付款或者其他原因失败,乙读到其实是假数据,称为脏读。
脏读(Dirty Read)
事务读取到未提交的数据。
READ COMMITTED(提交读)
在READ COMMITTED级别,一个事务开始时,只能“看见”已经提交的事务所做的修改。换句话说,一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。
这是多数数据库系统的默认隔离级别(但MySQL不是)。
在前面的例子中,设置这个级别,乙看到的将是100。同样可能导致的问题是,乙在一次事务中,查询成功后,甲付款成功,票数变为99,乙再次查询,结果由100变成99。一次事务中两次查询结果不一致,也叫不可重复读。
不可重复读(nonrepeatable read)
两次执行同样的查询,得到了不一样的结果。
REPEATABLE READ(可重复读)
可重复读是MySQL的默认事务隔离级别。
REPEATABLE READ解决了脏读的问题。保证了在同一个事务中多次读取同样记录的结果是一致的(意思是对同样的数据修改不影响)。
但是可重复读隔离级别无法解决幻读的问题。
幻读(Phantom Read)
所谓幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行(Phantom Row)。
MySQL关于幻读的处理
InnoDB和XtraDB存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)解决了幻读的问题。
InnoDB的MVCC是通过每一行加两个隐藏列来实现,一列记录行的创建时间,一列记录行的过期时间(或删除时间),实际记录的是版本号而非具体时间。 相当于行级锁,但是比加锁开销更低,也体现了一种用空间换时间的思想。详细内容参考文档或者相关书籍。
关于这个级别到底是否完全解决幻读问题,MySQL(8.0)文档是这样说的:
This is the default isolation level for InnoDB. Consistent reads within the same transaction read the snapshot established by the first read. This means that if you issue several plain (nonlocking) SELECT statements within the same transaction, these SELECT statements are consistent also with respect to each other.
For locking reads (SELECT with FOR UPDATE or FOR SHARE), UPDATE, and DELETE statements, locking depends on whether the statement uses a unique index with a unique search condition, or a range-type search condition.
For a unique index with a unique search condition, InnoDB locks only the index record found, not the gap before it.
For other search conditions, InnoDB locks the index range scanned, using gap locks or next-key locks to block insertions by other sessions into the gaps covered by the range.
如果在同一事务中发出多个普通(非锁定)SELECT语句,则这些SELECT语句彼此之间也是一致的。
对于锁定读取(使用FOR UPDATE或FOR SHARE进行SELECT),UPDATE和DELETE语句,锁定取决于该语句是使用具有唯一搜索条件的唯一索引还是范围类型搜索条件。
对于具有唯一搜索条件的唯一索引,InnoDB仅锁定找到的索引记录,而不锁定其前的间隙。
对于其他搜索条件,InnoDB使用间隔锁定或下一键锁定来锁定扫描的索引范围,以阻止其他会话插入该范围覆盖的间隔。
总结:如果是普通查询,能够避免幻读。对于锁定查询,只能在部分情况下(范围查询时)避免幻读。
SERIALIZABLE(可串行化)
SERIALIZABLE是最高的隔离级别。它通过强制事务串行执行,避免了前面说的幻读的问题。简单来说,SERIALIZABLE会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题。实际应用中也很少用到这个隔离级别,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑采用该级别。
总结:
因为实际业务需要,产生了事务,又因为事务本身的特性,需要考虑不同事务之间的可见性,产生了隔离级别。
四种隔离级别:
READ UNCOMMITTED=》READ COMMITTED=》REPEATABLE READ=》SERIALIZABLE
越低的级别能够执行更高的并发,系统开销也更低。
本文主要参考了《高性能mysql(第3版)》,以及MySQL8.0官方文档。
MySQL中事务和事务的隔离级别的更多相关文章
- Mysql加锁过程详解(6)-数据库隔离级别(2)-通过例子理解事务的4种隔离级别
Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...
- sql 事务的四种隔离级别
在 SQL 标准中定义了四种隔离级别,每一种级别都规定了一个事务中所做的修改,哪些在事务内和事务间是可见的,哪些是不可见的.较低级别的隔离通常可以执行更高的并发,系统的开销也更低. read unco ...
- 数据库事务ACID特性及隔离级别
数据库ACID特性介绍 1.原子性(Atomic)一个事务被视为一个不可分割的最小工作单元,这个事务里的所有操作要么全部成功执行,要么全都不执行,不能只执行其中的一部分操作.实现事务的原子性,要支持回 ...
- SQL Server事务的四种隔离级别
在SQL标准中定义了四种隔离级别,每一种级别都规定了一个事务中所做的修改,哪些是在事务内和事务间可见的,哪些是不可见的.较低级别的隔离通常可以执行更高的并发,系统的开销也更低. 1.未提交读(Read ...
- 事务特性ACID及隔离级别
注:例子引用来自:https://www.cnblogs.com/WJ-163/p/6023054.html 事务就是一组原子性的SQL查询,或者说一个独立的工作单元. 银行应用是解释事务必要性的一个 ...
- Spring事务传播机制与隔离级别(转)
Spring事务传播机制与隔离级别 博客分类: Spring 转自:http://blog.csdn.net/edward0830ly/article/details/7569954 (写的不错) ...
- spring事务传播属性和隔离级别
猫咪咪的Java世界 spring事务传播属性和隔离级别 博客分类: Spring java编程 1 事务的传播属性(Propagation) 1) REQUIRED ,这个是默认的属性 Supp ...
- 网络协议 finally{ return问题 注入问题 jdbc注册驱动问题 PreparedStatement 连接池目的 1.2.1DBCP连接池 C3P0连接池 MYSQL两种方式进行实物管理 JDBC事务 DBUtils事务 ThreadLocal 事务特性 并发访问 隔离级别
1.1.1 API详解:注册驱动 DriverManager.registerDriver(new com.mysql.jdbc.Driver());不建议使用 原因有2个: >导致驱动被注册2 ...
- [Mysql]——通过例子理解事务的4种隔离级别(转)
SQL标准定义了4种隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的. 低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销. 一.事务隔离级别分类 第1级别:R ...
- [Mysql]——通过例子理解事务的4种隔离级别
SQL标准定义了4种隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的. 低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销. 首先,我们使用 test 数据库, ...
随机推荐
- 如何用CMake构建Android C++库
https://fireflytech.org/2017/11/04/compiling-cc-libraries-for-android/ https://blog.csdn.net/xhp2014 ...
- LoadRunner回放脚本遇到的问题(遇到就补上)
问题一:Error-26612:HTTP Status-code=500(Internal Server Error) 解决过程:google找到了关于这个错误有多种解决的方法,但是都不是我要的,最重 ...
- 使用代码给Unity中的动画片段绑定回调函数
在制作动作游戏的时候,需要播放许多动画,同时还有个需求,那就是动画播放到一定时间时,给一个回调函数,好做对应的状态变更, 我查了一下,发现如果使用的是unity自带的动画系统,要做到这样的话,需要这样 ...
- 深入了解Netty【五】线程模型
引言 不同的线程模型对程序的性能有很大的影响,Netty是建立在Reactor模型的基础上,要搞清Netty的线程模型,需要了解一目前常见线程模型的一些概念. 具体是进程还是线程,是和平台或者编程语言 ...
- Prmise.all的简单实现
注意点 入参一般是个由Promise实例组成的数组,但是也可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例.若参数如果不是 Promise 实例,就会先调用 ...
- apache常见错误:VC运行库(找不到 VCRUNTIME140.dll)
1. 安装apache为系统服务时报错:找不到 VCRUNTIME140.dll 解决方案:安装 VC2015 2. 下载并安装 VC2015 运行库, 运行 VC_redist.x64.exe 无脑 ...
- 获取JSO字符串的key和value值
import com.alibaba.fastjson.JSON; import java.util.ArrayList; import java.util.HashMap; import java. ...
- 如何把自己开发的项目上传到GitHub仓库或者码云仓库?
首先你需要用你的邮箱去注册一个自己的GitHub仓库 or 码云仓库.然后确保你的电脑安装了git. 码云仓库:https://gitee.com/ GitHub:https://github.com ...
- 第9课 - const 和 volatile分析
第9课 - const和volatile分析 1. const只读变量 (1)const修饰的变量是只读的,本质上还是变量,并不是真正意义上的常量 ※※ const只是告诉编译器该变量 ...
- gcc之__attribute__简介及对齐参数介绍
GNU C的一大特色就是__attribute__机制.__attribute__机制可以设置函数属性(Function Attribute).变量属性(Variable Attribute)和类型属 ...