MySQL 4种事务的隔离级别

news/2024/7/4 23:49:34

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

 

事务的ACID:

    1)原子性(Atomic):事务中各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败;

    2)一致性(Consistent):事务结束后系统状态是一致的;

    3)隔离性(Isolated):并发执行的事务彼此无法看到对方的中间状态;

    4)持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难性的失败。通过日志和同步备份可以在故障发生后重建数据。

如果不考虑事务的隔离性,会出现以下问题:

  • 幻读(Phantom Read):事务A重新执行一个查询,返回一系列符合查询条件的行,发现其中插入了被事务B提交的行。
  • 不可重复读(Unrepeatable Read):事务A重新读取前面读取过的数据,发现该数据已经被另一个已提交的事务B修改过了。
  • 脏读(Dirty Read):A事务读取B事务尚未提交的数据并在此基础上操作,而B事务执行回滚,那么A读取到的数据就是脏数据。

    小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

隔离级别:

隔离级别脏读(Dirty Read)不可重复读(NonRepeatable Read)幻读(Phantom Read)
未提交读(Read uncommitted)可能可能可能    
已提交读(Read committed)不可能可能可能
可重复读(Repeatable read)不可能不可能可能
可串行化(Serializable )不可能不可能不可能

级别越高,数据越安全,但性能越低。

Oracle和SQL Server 默认隔离级别为 已提交读(Read committed)

MySQL 默认隔离级别为 可重复读(Repeatable read)

一个事务怎么会干扰其他事务呢?

咱们举例子来说明,假设有InnoDB表:

t(id PK, name);

 

表中有三条记录:

1, shenjian

2, zhangsan

3, lisi

 

case 1

事务A,先执行,处于未提交的状态:

insert into t values(4, wangwu);

 

事务B,后执行,也未提交:

select * from t;

 

如果事务B能够读取到(4, wangwu)这条记录,事务A就对事务B产生了影响,这个影响叫做“读脏”,读到了未提交事务操作的记录。

 

case 2

事务A,先执行:

select * from t where id=1;

 

结果集为:

1, shenjian

 

事务B,后执行,并且提交:

update t set name=xxoo where id=1;

commit;

 

事务A,再次执行相同的查询:

select * from t where id=1;

 

结果集为:

1, xxoo

 

这次是已提交事务B对事务A产生的影响,这个影响叫做“不可重复读”,一个事务内相同的查询,得到了不同的结果。

 

case 3

事务A,先执行:

select * from t where id>3;

 

结果集为:

NULL

 

事务B,后执行,并且提交:

insert into t values(4, wangwu);

commit;

 

事务A,首次查询了id>3的结果为NULL,于是想插入一条为4的记录:

insert into t values(4, xxoo);

 

结果集为:

Error : duplicate key!

 

事务A的内心OS是:你TM在逗我,查了id>3为空集,insert id=4告诉我PK冲突?

 

这次是已提交事务B对事务A产生的影响,这个影响叫做“幻读”。

 

可以看到,并发的事务可能导致其他事务:

  • 读脏

  • 不可重复读

  • 幻读

 

不同事务的隔离级别,实际上是一致性与并发性的一个权衡与折衷。

 

InnoDB的四种事务的隔离级别,分别是怎么实现的?

InnoDB使用不同的锁策略(Locking Strategy)来实现不同的隔离级别。

 

一,读未提交(Read Uncommitted)

这种事务隔离级别下,select语句不加锁。

画外音:官方的说法是

SELECT statements are performed in a nonlocking fashion.

 

此时,可能读取到不一致的数据,即“读脏”。这是并发最高,一致性最差的隔离级别。

 

二,串行化(Serializable)

这种事务的隔离级别下,所有select语句都会被隐式的转化为select ... in share mode.

 

这可能导致,如果有未提交的事务正在修改某些行,所有读取这些行的select都会被阻塞住。

画外音:官方的说法是

To force a plain SELECT to block if other transactions have modified the selected rows.

 

这是一致性最好的,但并发性最差的隔离级别。

 

在互联网大数据量,高并发量的场景下,几乎不会使用上述两种隔离级别。

 

三,可重复读(Repeated Read, RR)

这是InnoDB默认的隔离级别,在RR下:

 

(1)普通的select使用快照读(snapshot read),这是一种不加锁的一致性读(Consistent Nonlocking Read),底层使用MVCC来实现,具体的原理在《InnoDB并发如此高,原因竟然在这?》中有详细的描述;

 

(2)加锁的select(select ... in share mode / select ... for update), update, delete等语句,它们的锁,依赖于它们是否在唯一索引(unique index)上使用了唯一的查询条件(unique search condition),或者范围查询条件(range-type search condition):

  • 在唯一索引上使用唯一的查询条件,会使用记录锁(record lock),而不会封锁记录之间的间隔,即不会使用间隙锁(gap lock)与临键锁(next-key lock)

  • 范围查询条件,会使用间隙锁与临键锁,锁住索引记录之间的范围,避免范围间插入记录,以避免产生幻影行记录,以及避免不可重复的读

画外音:这一段有点绕,多读几遍。

 

关于记录锁,间隙锁,临键锁的更多说明,详见《InnoDB,select为啥会阻塞insert?》。

 

四,读提交(Read Committed, RC)

这是互联网最常用的隔离级别,在RC下:

 

(1)普通读是快照读;

 

(2)加锁的select, update, delete等语句,除了在外键约束检查(foreign-key constraint checking)以及重复键检查(duplicate-key checking)时会封锁区间,其他时刻都只使用记录锁;

 

此时,其他事务的插入依然可以执行,就可能导致,读取到幻影记录。

 

总结

  • 并发事务之间相互干扰,可能导致事务出现读脏,不可重复度,幻读等问题

  • InnoDB实现了SQL92标准中的四种隔离级别

(1)读未提交:select不加锁,可能出现读脏;

(2)读提交(RC):普通select快照读,锁select /update /delete 会使用记录锁,可能出现不可重复读;

(3)可重复读(RR):普通select快照读,锁select /update /delete 根据查询条件情况,会选择记录锁,或者间隙锁/临键锁,以防止读取到幻影记录;

(4)串行化:select隐式转化为select ... in share mode,会被update与delete互斥;

InnoDB默认的隔离级别是RR,用得最多的隔离级别是RC

 

对比Oracle :

相对mysql ,oracle的事务分显示提交,隐式提交,自动提交。

显示提交必须手动敲入commit或rollback命令。DML必须显示提交,包括的命令:update、insert、delete,这几个很好理解,但select也需要显示提交,有点难理解,select只是个查询语句,而且select似乎是DQL不是DML。我们可以考虑下select into from语句,select into是一个plsql语言中的复制语句,和:=实现的目标一样。

隐式提交就是DDL、DCL,包括create、drop、alter,grant、revoke。

转载于:https://my.oschina.net/rechardchensir/blog/1938565


http://www.niftyadmin.cn/n/2132471.html

相关文章

基于随机无迹sigma点变异策略的改进哈里斯鹰优化算法

文章目录一、理论基础1、哈里斯鹰优化算法2、改进的哈里斯鹰优化算法(1)反向学习策略(2)非线性收敛因子调整策略(3)随机无迹sigma点变异策略(4)IHHO算法流程图二、仿真实验与结果分析…

GO语言学习笔记(三) - 递归查找目录及子目录下的文件

GO语言学习笔记(三) - 递归查找目录及子目录下的文件 递归查找目录及子目录下的文件递归查找文件夹及子文件夹下的文件 代码 package mainimport ("fmt""io/ioutil""os""strings" )// 查找目录及子目录下的文件…

一种基于金鹰优化和灰狼优化的混合算法

文章目录一、理论基础1、金鹰优化算法2、灰狼优化算法3、提出的混合算法3.1 个体示例学习GEO(PELGEO)3.2 差分变异的简化GWO(DMSGWO)3.2.1 差分变异策略3.2.2 简化策略3.2.3 混合差异变异策略和简化策略3.3 自适应混合策略二、仿真实验与结果分析三、参考文献一、理论基础 1、…

算术优化与阿奎拉鹰优化的混合算法

文章目录一、理论基础1、阿奎拉鹰优化算法2、算术优化算法3、AO与AOA的混合(AOAAO)(1)改进逃逸能量参数(2)AOAAO算法伪代码二、仿真实验与结果分析三、参考文献一、理论基础 1、阿奎拉鹰优化算法 请参考这里。 2、算术优化算法…

酒瓶换酒

""" 一开始有5瓶啤酒 两个空酒瓶换一瓶啤酒 四个瓶盖换一瓶啤酒 问你最后能够喝到多少瓶啤酒 """def get(n):bottle, head n, ndrink 0while 1:drink bottleuse bottle // 2 head // 4if use 0:breakbottle % 2head % 4bottle usehead u…

基于随机无迹σ变异的改进HHO算法

文章目录一、理论基础1、哈里斯鹰优化算法HHO2、改进哈里斯鹰优化算法OSHHO(1)伪对立和伪反射学习机制(2)随机无迹点变异机制(3)能量因子非线性调整机制(4)OSHHO算法执行流程二、仿真…

基于亨利气体溶解度优化算法的函数寻优算法

文章目录一、理论基础1、亨利气体溶解度优化算法(1)步骤1:初始化过程(2)步骤2:分簇(3)步骤3:评价(4)步骤4:更新亨利系数(5…

JavaScript继承总结

1.创建对象 1.字面量对象2.构造函数3.Object.create //1.字面量 var obj{name: 字面量,show: function(){console.log(this.name)} } //2.构造函数 function fun (name) {this.namename } var objnew fun(obj) //3.Object.create var obj{name: obj} var objObject.create(obj)…