数据库事务的隔离级别有4种,由低到高分别为Read uncommitted 、Read committed 、Repeatable read 、Serializable 。并且,在事务的并发操做中可能会出现脏读,不可重复读,幻读。下面经过事例一一阐述它们的概念与联系。mysql
脏读、不可重复读、幻象读概念说明: 程序员
脏读:指当一个事务正在访问数据,而且对数据进行了修改,而这种数据尚未提交到数据库中,这时,另一个事务也访问这个数据,而后使用了这个数据。由于这个数据尚未提交那么另一个事务读取到的这个数据咱们称之为脏数据。依据脏数据所作的操做肯能是不正确的。
不可重复读:指在一个事务内,屡次读同一数据。在这个事务尚未执行结束,另一个事务也访问该同一数据,那么在第一个事务中的两次读取数据之间,因为第二个事务的修改第一个事务两次读到的数据多是不同的,这样就发生了在一个事物内两次连续读到的数据是不同的,这种状况被称为是不可重复读。
幻象读:一个事务前后读取一个范围的记录,但两次读取的纪录数不一样,咱们称之为幻象读(两次执行同一条 select 语句会出现不一样的结果,第二次读会增长一数据行,并无说这两次执行是在同一个事务中)sql
读未提交 (Read uncommitted)数据库
读未提交,顾名思义,就是一个事务能够读取另外一个未提交事务的数据。并发
事例:老板要给程序员发工资,程序员的工资是3.6万/月。可是发工资时老板不当心按错了数字,按成3.9万/月,该钱已经打到程序员的户口,可是事务尚未提交,就在这时,程序员去查看本身这个月的工资,发现比往常多了3千元,觉得涨工资了很是高兴。可是老板及时发现了不对,立刻回滚差点就提交了的事务,将数字改为3.6万再提交。mvc
分析:实际程序员这个月的工资仍是3.6万,可是程序员看到的是3.9万。他看到的是老板还没提交事务时的数据。这就是脏读。所以,在这种隔离级别下,查询是不会加锁的,也因为查询的不加锁,因此这种隔离级别的一致性是最差的,可能会产生“脏读”、“不可重复读”、“幻读”。如无特殊状况,基本是不会使用这种隔离级别的。ide
那怎么解决脏读呢?Read committed!读提交,能解决脏读问题。高并发
读提交(Read Committed)性能
读提交,顾名思义,就是只能读到已经提交了的内容spa
事例:程序员拿着信用卡去享受生活(卡里固然是只有3.6万),当他埋单时(程序员事务开启),收费系统事先检测到他的卡里有3.6万,就在这个时候!!程序员的妻子要把钱所有转出充当家用,并提交。当收费系统准备扣款时,再检测卡里的金额,发现已经没钱了(第二次检测金额固然要等待妻子转出金额事务提交完)。程序员就会很郁闷,明明卡里是有钱的…
分析:这就是读提交,如有事务对数据进行更新(UPDATE)操做时,读操做事务要等待这个更新操做事务提交后才能读取数据,能够解决脏读问题。但在这个事例中,出现了一个事务范围内两个相同的查询却返回了不一样数据,这就是不可重复读。
这是各类系统中最经常使用的一种隔离级别,也是SQL Server和Oracle的默认隔离级别。这种隔离级别可以有效的避免脏读,但除非在查询中显示的加锁,如:
select * from T where ID=2 lock in share mode; select * from T where ID=2 for update;
否则,普通的查询是不会加锁的。
那为何“读提交”同“读未提交”同样,都没有查询加锁,可是却可以避免脏读呢?
这就要说道另外一个机制“快照(snapshot)”,而这种既能保证一致性又不加锁的读也被称为“快照读(Snapshot Read)”
假设没有“快照读”,那么当一个更新的事务没有提交时,另外一个对更新数据进行查询的事务会由于没法查询而被阻塞(由于上了X锁,即写锁,因此不能获得S锁,即读锁),这种状况下,并发能力就至关的差。而“快照读”就能够完成高并发的查询,不过,“读提交”只能避免“脏读”,并不能避免“不可重复读”和“幻读”。
那怎么解决可能的不可重复读问题?Repeatable read !
可重复读(Repeated Read)
可重复读,顾名思义,就是专门针对“不可重复读”这种状况而制定的隔离级别,天然,它就能够有效的避免“不可重复读”。而它也是MySql的默认隔离级别。
事例:程序员拿着信用卡去享受生活(卡里固然是只有3.6万),当他埋单时(事务开启,不容许其余事务的UPDATE修改操做),收费系统事先检测到他的卡里有3.6万。这个时候他的妻子不能转出金额了。接下来收费系统就能够扣款了。
分析:重复读能够解决不可重复读问题。写到这里,应该明白的一点就是,不可重复读对应的是修改,即UPDATE操做。可是可能还会有幻读问题。由于幻读问题对应的是插入INSERT操做,而不是UPDATE操做。
何时会出现幻读?
事例:程序员某一天去消费,花了2千元,而后他的妻子去查看他今天的消费记录(全表扫描FTS,妻子事务开启),看到确实是花了2千元,就在这个时候,程序员花了1万买了一部电脑,即新增INSERT了一条消费记录,并提交。当妻子打印程序员的消费记录清单时(妻子事务提交),发现花了1.2万元,彷佛出现了幻觉,这就是幻读。
在这个级别下,普通的查询一样是使用的“快照读”,可是,和“读提交”不一样的是,当事务启动时,就不容许进行“修改操做(Update)”了,而“不可重复读”偏偏是由于两次读取之间进行了数据的修改,所以,“可重复读”可以有效的避免“不可重复读”,但却避免不了“幻读”,由于幻读是因为“插入或者删除操做(Insert or Delete)”而产生的。
那怎么解决幻读问题?Serializable!
序列化 Serializable
这是数据库最高的隔离级别,这种级别下,事务“串行化顺序执行”,也就是一个一个排队执行。这种级别下,“脏读”、“不可重复读”、“幻读”均可以被避免,可是执行效率奇差,性能开销也最大,因此基本没人会用。
值得一提的是:大多数数据库默认的事务隔离级别是Read committed,好比Sql Server , Oracle。Mysql的默认隔离级别是Repeatable read。
MySql如何解决幻读问题?
(1)什么是幻读
在一次事务里面,屡次查询以后,结果集的个数不一致的状况叫作幻读。而多出来或者少的哪一行被叫作 幻行
(2)幻读产生的缘由
行锁只能锁住行,即便把全部的行记录都上锁,也阻止不了新插入的记录。
(3)如何解决幻读?
备注:什么是快照读、当前读
- 快照读, 读取专门的快照 (对于RC,快照(ReadView)会在每一个语句中建立。对于RR,快照是在事务启动时建立的)
```
简单的select操做便可(不须要加锁,如: select ... lock in share mode, select ... for update)
```
针对的也是select操做
- 当前读, 读取最新版本的记录, 没有快照。 在InnoDB中,当前读取根本不会建立任何快照。
```
select ... lock in share mode
select ... for update
insert
update
delete
针对以下操做, 会让以下操做阻塞:
```
insert
update
delete
```
- 在RR(可重复读)级别下, 快照读是经过MVVC(多版本控制)和undo log来实现的,
当前读是经过手动加record lock(记录锁)和gap lock(间隙锁)来实现的。因此从上面的显示来看,若是须要实时显示数据,仍是须要经过加锁来实现。这个时候会使用next-key技术来实现。因此说
总结一下:
出处:https://blog.csdn.net/qq_33290787/article/details/51924963
https://baijiahao.baidu.com/s?id=1611918898724887602&wfr=spider&for=pc