图解MySQL事务隔离级别

本文主要通过大量的实例截图,来通俗的讲解MySQL的四种事务隔离级别的效果。关于事务隔离级别的概念以及不同隔离级别会引发的问题,大家可以自行百度,此处不再赘述。

标准数据库的四种事务隔离级别,不同隔离级别会引发的问题:

隔离级别 脏读 不可重复读 幻读
Read Uncommitted Y Y Y
Read Committed N Y Y
Repeatable Read N N Y
Serializable N N N

MySQL采用的默认隔离级别是Repeatable Read,我们可以用set global|session tx_isolation=‘xxx‘和select @@global|session.tx_isolation来修改和查看global或session的隔离级别。下面我们一一介绍不同隔离级别在‘增删改’操作时的效果。



1. Read Uncommitted
当前数据库的隔离级别为Read Uncommitted

①增:
session1开启事务,往company表插入一条数据,成功:

session2开启事务,查询company表,session1插入的未提交数据对session2可见。这就出现了脏读和幻读,因为对于session2来说莫名其妙的多出了一条未提交的数据;而且出现了不可重复读,因为这次读到的记录跟上一次读到的不一样:

如果session2在不知情的情况下,又往数据库insert一条company_id为6的数据;又或者他以为company_id为6的数据是已经commit的数据,要对他进行update或者delete操作。那这些操作都会阻塞,直到session1完成事务为止,因为这条数据还在session1事务的管理中,后面可能还会发生变化:

但如果session2不是修改的session1插入的数据,update、insert和delete是可以成功的,因为InnoDB采用的是行锁:

②删:
session1开启事务,并从company表中删除一条记录:

session2开启事务,查询company表,session1删除后未提交数据对session2可见,典型的脏读。也出现了幻读,因为对于session2来说莫名其妙的少出了一条数据,而且出现了不可重复读,因为这次读到的记录跟上一次读到的不一样:

跟上面一样,如果session2对session1事务中操作的记录进行delete、insert和update会被阻塞,直到session1结束事务并释放行锁。而对其他行的delete、insert和update操作可以成功:

③改:
session1开启事务,并修改company表中的一条记录:

session2开启事务,查询company表,session1修改后未提交数据对session2可见。但没有出现了幻读,因为对于session2来说数据量并没有改变,但出现了脏读和不可重复读,因为这次读到了session1未提交的修改数据而且记录跟上一次读到的不一样:

跟上面一样,如果session2对session1事务中操作的记录进行delete、insert和update会被阻塞,直到session1结束事务并释放行锁。而对其他行的delete、insert和update操作可以成功:

总结:Read Uncommitted隔离级别会出现:脏读、不可重复读和幻读。每个session在事务中的操作会对其他session事务立即可见,哪怕是未提交的操作。但当前session事务正在操作的数据,只要当前事务没有结束或者回滚,就无法被其他session修改,其他session会阻塞。



2. Read Committed
当前数据库的隔离级别为Read Committed

①增:
session1开启事务,往company表插入一条数据,成功并且session1可以看到这条记录:

session2开启事务,查询company表,session1插入的未提交数据对session2不可见。在session1没有提交之前不会出现幻读和不可重复读:

但只要session1一提交就会出现幻读和不可重复读:

如果session2对session1事务中操作的记录进行delete、insert和update会被阻塞,直到session1结束事务并释放行锁。而对其他行的delete、insert和update操作可以成功:
②删:
session1开启事务,并从company表中删除一条记录:

session2开启事务,查询company表,session1删除后未提交数据对session2不可见。当然也没有出现幻读和不可重复读:

但只要session1一提交就会出现幻读和不可重复读:


跟上面一样,如果session2对session1事务中操作的记录进行delete、insert和update会被阻塞,直到session1结束事务并释放行锁。而对其他行的delete、insert和update操作可以成功。
③改:
session1开启事务,并修改company表中的一条记录:

session2开启事务,查询company表,session1修改后未提交数据对session2不可见。没有出现了幻读、脏读和不可重复读:

但只要session1一提交就会出现不可重复读:


跟上面一样,如果session2对session1事务中操作的记录进行delete、insert和update会被阻塞,直到session1结束事务并释放行锁。而对其他行的delete、insert和update操作可以成功。

总结:Read Committed隔离级别会出现:不可重复读和幻读。每个session在事务中的操作对其他session事务是不可见的。当前session事务中正在操作的数据,只要当前事务没有结束或者回滚,就无法被其他session修改,其他session会阻塞。一旦提交就可能会出现不可重复读和幻读。



3.Repeatable Read
当前数据库的隔离级别为Repeatable Read

①增:
session1开启事务,往company表插入一条数据,成功:

session2开启事务,查询company表,session1删除后未提交数据对session2不可见。当然也没有出现幻读和不可重复读:

session1提交后,session2也不会出现不可重复读:

不是说Repeatable Read会出现幻读么,这里为什么没有多出一条记录?其实Repeatable Read隔离级别可以保证每次读取都是一样的记录,幻读只是说如果session2正在insert的数据和被session1插入的数据相同时会报duplicate key的错,因为session1已经插入了。这样让用户就会感到奇怪,为什么明明没有记录却无法插入呢:

②删:
session1开启事务,并从company表中删除一条记录:

session2开启事务,查询company表,session1删除后未提交数据对session2不可见。当然也没有出现幻读和不可重复读:

session1提交后,session2也不会出现不可重复读。但幻读存在,因为如果我们去delete或者update session1已经删掉的记录时,会显示受影响的记录为0;而去insert一个跟删掉的记录同样company_id的记录却可以成功,说明记录实际上已经不存在了:


③改:
session1开启事务,并修改company表中的一条记录:

session2开启事务,查询company表,session1修改后未提交数据对session2不可见。没有出现了幻读、脏读和不可重复读:

session1提交后,session2也不会出现不可重复读。跟上面一样幻读依旧存在,如果我们去根据session1修改后的条件去update或者delete记录时可以成功,说明记录实际上已经被修改了:

总结:Repeatable Read隔离级别会出现:幻读。每个session在事务中的操作对其他session事务是不可见的。当前session事务中正在操作的数据,只要当前事务没有结束或者回滚,就无法被其他session修改,其他session会阻塞。一旦提交就可能会出现幻读。所以Repeatable Read相当于生成一个数据库记录的快照,表面上每次读取的数据都一样吗,但实际上有可能已经发生了变化。



4.Serializable
当前数据库的隔离级别为Serializable

Serializable主要是使用InnoDB的行锁来实现的,增删改都是加行锁,所以下面就只讨论增的情况:
session1开启事务,往company表插入一条数据,成功:

session2开启事务,查询company表时直接被阻塞,查询刚插入的数据时也被阻塞,但查询其他数据时却没问题。说明采用Serializable隔离级别时,利用了InnoDB行锁的特性,谁修改列谁就能获得列的写锁,所以其他session是无法读取和写入的。第一个全表查询包括了刚被session1插入的数据,所以被阻塞:

如果我们现在回到session1里面去修改company_id=1的记录可以成功吗?结果是被阻塞,因为该记录已经被session2读取的同时也被session2加上了读锁。所以session1可以读取,但无法写入:

这种情况下脏读、不可重复读和幻读都不可能出现,因为其他事务修改的记录,当前事务根本没机会读取;而被当前事务读取的数据,其他事务根本没机会修改。

Serializable是一种完全同步机制,所以很容易出现死锁,所以要特别注意,下面我们来看看死锁的例子:
首先session1和session2分别取出company_id为1和2的两条数据,根据上面的例子我们可以知道,session1会给company_id=1的记录加读锁,session2也会给company_id=2的记录加读锁:


然后让session1去更新company_id=2的记录,肯定被阻塞;再让session2区更新company_id=1的记录,这时MySQL就会告诉我们出现了死锁,并强制关闭了session2的事务,让session1更新成功。之所以会出现死锁,因为session1要等待session2释放company_id=2的记录的读锁,而session2又要等待session1释放company_id=1的记录的读锁:

总结:Serializable主要是使用InnoDB的行锁来实现的,在事务中只要select出来的行都会被当前session加上read锁,如果去修改有read锁的行会被升级为write锁,没有read锁的行则直接加write锁。所以Serializable隔离级别不会出现脏读、不可重复读和幻读(第一次读的时候已经给行加read锁,其他session根本无法修改select出来的行,所以就保证了多次读取的一致性)

时间: 2024-11-05 17:00:12

图解MySQL事务隔离级别的相关文章

查询mysql事务隔离级别

查询mysql事务隔离级别 查询mysql事务隔离级别 分类: DB2011-11-26 13:12 2517人阅读 评论(0) 收藏 举报 mysqlsessionjava 1.查看当前会话隔离级别 select @@tx_isolation; 2.查看系统当前隔离级别 select @@global.tx_isolation; 3.设置当前会话隔离级别 set session transaction isolatin level repeatable read; 4.设置系统当前隔离级别 s

Mysql事务-隔离级别

MYSQL事务-隔离级别 事务是什么? 事务简言之就是一组SQL执行要么全部成功,要么全部失败.MYSQL的事务在存储引擎层实现. 事务都有ACID特性: 原子性(Atomicity):一个事务必须被视为一个不可分割的单元: 一致性(Consistency):数据库总是从一种状态切换到另一种状态: 隔离性(Isolation):通常来说,事务在提交前对于其他事务不可见: 持久性(Durablity):一旦事务提交,所做修改永久保存数据库: 事务最常用的例子就是银行转账.假设polo需给lynn转

MySQL事务隔离级别为"REPEATABLE-READ"下的"幻读"现象

MySQL事务隔离级别为"REPEATABLE-READ"下的"幻读"现象 关于mysql命令行中事务控制的语句见该文章:http://my.oschina.net/xinxingegeya/blog/296459 本片参考文章:http://blog.csdn.net/jiao_fuyou/article/details/16368827 http://www.cnblogs.com/hancf/archive/2012/08/28/2660422.html my

MySQL事务隔离级别详解

SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的.低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销.Read Uncommitted(读取未提交内容) 在该隔离级别,所有事务都可以看到其他未提交事务的执行结果.本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少.读取未提交的数据,也被称之为脏读(Dirty Read).Read Committed(读取提交内容) 这是大多数数据库系统的默认隔离级别(但不是MySQL默认的).

查询修改mysql事务隔离级别

1.查看当前会话隔离级别 select @@tx_isolation; 2.查看系统当前隔离级别 select @@global.tx_isolation; 3.设置当前会话隔离级别 set tx_isolation='read-committed'; 4.设置系统当前隔离级别 set global transaction isolation level read committed; 关于隔离级别的理解: 1.read uncommitted 可以看到未提交的数据(脏读),举个例子:别人说的话

mysql -- 事务隔离级别以及java中事务提交的步骤

SQL标准定义了四种隔离级别,不同隔离的级别使用不当会出现脏读.不可重复读和幻读的问题,隔离级别的出现是事务处理效率与安全的一种平衡. 隔离级别不同会出现的问题 脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的. 不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据. 幻读(Phant

mysql事务隔离级别与锁的关系

其实操作了这么久mysql一直也没有把mysql中事务跟锁的关系弄得特别清楚.然后搜到美团这篇文章,顺便结合一下自己遇到的问题总结一下. 首先事务有四种隔离级别: Reference: http://tech.meituan.com/innodb-lock.html Innodb中的事务隔离级别和锁的关系

Mysql事务隔离级别学习

这篇文章主要谈谈Mysql事务隔离级别的区别,以及自己的一些感受. 自己一直以来没搞懂“可重复读”和可提交读“两者之间的区别,通过此次的实践,清楚了两者之间的区别.废话不说,先上图看看这几个事务隔离级别. Mysql数据库总共分为四个事务隔离级别,其中默认的事务隔离级别是:repeatable read,而与其它的数据库不同的是,其它的数据库默认事务隔离级别是read committed(SQL Server.Oracle). 第一步:SERIALIZABLE Instance 1: Insta

事务以及MySQL事务隔离级别+MySQL引擎的区别

1.事务的基本要素:ACID 1.原子性(Atomicity): 事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节.事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样.也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位. 2.一致性(Consistency): 事务开始前和结束后,数据库的完整性约束没有被破坏 .比如 A 向 B 转账,不可能 A 扣了钱,B 却没收到. 3.隔离性(Isolation): 同一时间,只允许一个事