数据库常用的事务隔离级别都有哪些?都是什么原理?

数据库 MySQL
任何支持事务的数据库,都必须具备四个特性,分别是:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability),也就是我们常说的事务ACID,这样才能保证事务((Transaction)中数据的正确性。

 什么是事务隔离?

任何支持事务的数据库,都必须具备四个特性,分别是:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability),也就是我们常说的事务ACID,这样才能保证事务((Transaction)中数据的正确性。 

 

[[246426]] 

而事务的隔离性就是指,多个并发的事务同时访问一个数据库时,一个事务不应该被另一个事务所干扰,每个并发的事务间要相互进行隔离。

如果没有事务隔离,会出现什么样的情况呢?

假设我们现在有这样一张表(T),里面记录了很多牛人的名字,我们不进行事务的隔离看看会发生什么呢? 

[[246427]] 

***天,事务A访问了数据库,它干了一件事情,往数据库里加上了新来的牛人的名字,但是没有提交事务。 

  1. insert into T values (4, '牛D'); 

这时,来了另一个事务B,他要查询所有牛人的名字。 

  1. select Name from T; 

这时,如果没有事务之间没有有效隔离,那么事务B返回的结果中就会出现“牛D”的名字。这就是“脏读(dirty read)”。

第二天,事务A访问了数据库,他要查看ID是1的牛人的名字,于是执行了 

  1. select Name from T where ID = 1

这时,事务B来了,因为ID是1的牛人改名字了,所以要更新一下,然后提交了事务。 

  1. update T set Name = '不牛' where ID = 1

接着,事务A还想再看看ID是1的牛人的名字,于是又执行了 

  1. select Name from T where ID = 1

结果,两次读出来的ID是1的牛人名字竟然不相同,这就是不可重复读(unrepeatable read)。 

[[246428]] 

第三天,事务A访问了数据库,他想要看看数据库的牛人都有哪些,于是执行了 

  1. select * from T; 

这时候,事务B来了,往数据库加入了一个新的牛人。 

  1. insert into T values(4, '牛D'); 

这时候,事务A忘了刚才的牛人都有哪些了,于是又执行了。 

  1. select * from T; 

结果,***次有三个牛人,第二次有四个牛人。

相信这个时候事务A就蒙了,刚才发生了什么?这种情况就叫“幻读(phantom problem)”。 

[[246429]] 

为了防止出现脏读、不可重复读、幻读等情况,我们就需要根据我们的实际需求来设置数据库的隔离级别。

数据库都有哪些隔离级别呢?

一般的数据库,都包括以下四种隔离级别:

  1. 读未提交(Read Uncommitted)
  2. 读提交(Read Committed)
  3. 可重复读(Repeated Read)
  4. 串行化(Serializable)

如何使用这些隔离级别,那就需要根据业务的实际情况来进行判断了。

我们接下来就看看这四个隔离级别的具体情况

读未提交(Read Uncommitted)

读未提交,顾名思义,就是可以读到未提交的内容。

因此,在这种隔离级别下,查询是不会加锁的,也由于查询的不加锁,所以这种隔离级别的一致性是最差的,可能会产生“脏读”、“不可重复读”、“幻读”。

如无特殊情况,基本是不会使用这种隔离级别的。

读提交(Read Committed)

读提交,顾名思义,就是只能读到已经提交了的内容。

这是各种系统中最常用的一种隔离级别,也是SQL Server和Oracle的默认隔离级别。这种隔离级别能够有效的避免脏读,但除非在查询中显示的加锁,如: 

  1. select * from T where ID=2 lock in share mode;  
  2. select * from T where ID=2 for update;  

不然,普通的查询是不会加锁的。

那为什么“读提交”同“读未提交”一样,都没有查询加锁,但是却能够避免脏读呢?

这就要说道另一个机制“快照(snapshot)”,而这种既能保证一致性又不加锁的读也被称为“快照读(Snapshot Read)” 

[[246430]] 

假设没有“快照读”,那么当一个更新的事务没有提交时,另一个对更新数据进行查询的事务会因为无法查询而被阻塞,这种情况下,并发能力就相当的差。

而“快照读”就可以完成高并发的查询,不过,“读提交”只能避免“脏读”,并不能避免“不可重复读”和“幻读”。

可重复读(Repeated Read)

可重复读,顾名思义,就是专门针对“不可重复读”这种情况而制定的隔离级别,自然,它就可以有效的避免“不可重复读”。而它也是MySql的默认隔离级别。

在这个级别下,普通的查询同样是使用的“快照读”,但是,和“读提交”不同的是,当事务启动时,就不允许进行“修改操作(Update)”了,而“不可重复读”恰恰是因为两次读取之间进行了数据的修改,因此,“可重复读”能够有效的避免“不可重复读”,但却避免不了“幻读”,因为幻读是由于“插入或者删除操作(Insert or Delete)”而产生的。

串行化(Serializable)

这是数据库***的隔离级别,这种级别下,事务“串行化顺序执行”,也就是一个一个排队执行。

这种级别下,“脏读”、“不可重复读”、“幻读”都可以被避免,但是执行效率奇差,性能开销也***,所以基本没人会用。

总结一下

为什么会出现“脏读”?因为没有“select”操作没有规矩。

为什么会出现“不可重复读”?因为“update”操作没有规矩。

为什么会出现“幻读”?因为“insert”和“delete”操作没有规矩。

“读未提(Read Uncommitted)”能预防啥?啥都预防不了。

“读提交(Read Committed)”能预防啥?使用“快照读(Snapshot Read)”,避免“脏读”,但是可能出现“不可重复读”和“幻读”。

“可重复读(Repeated Red)”能预防啥?使用“快照读(Snapshot Read)”,锁住被读取记录,避免出现“脏读”、“不可重复读”,但是可能出现“幻读”。

“串行化(Serializable)”能预防啥?排排坐,吃果果,有效避免“脏读”、“不可重复读”、“幻读”,不过效果谁用谁知道。

 

责任编辑:庞桂玉 来源: 今日头条
相关推荐

2020-03-05 09:33:15

数据库事务隔离事务

2023-10-11 08:09:53

事务隔离级别

2018-07-17 10:58:45

数据库数据库事务隔离级别

2018-07-20 11:10:21

数据库事务隔离性

2023-06-01 07:37:48

级别事务调度

2018-01-03 08:52:27

MySQL数据库级别

2018-09-06 14:53:39

数据库事务隔离隔离级别

2009-06-29 17:54:47

Spring事务隔离

2010-11-19 16:13:06

oracle事务隔离级

2018-12-19 16:46:38

MySQL事务隔离数据库

2020-04-01 17:26:57

MySQL事务隔离级别数据库

2024-09-19 08:10:54

2021-08-04 13:19:42

MySQL 事务隔离

2021-07-26 10:28:13

MySQL事务隔离

2024-04-26 09:17:20

MySQL事务隔离

2022-12-14 08:00:00

数据库分布式数据库隔离

2021-10-11 19:30:02

分布式事务CAP

2023-12-26 09:34:43

MySQL数据库优化

2022-09-13 13:49:05

数据库隔离

2021-01-18 11:49:26

面试事务隔离
点赞
收藏

51CTO技术栈公众号