事务隔离级别

一、事务的四大特性

事务就是一组原子性的SQL查询,或者说一个独立的工作单元。如果数据库引擎能够成功地对数据库应用该组查询的全部语句,那么就执行该组查询。如果其中有任何一条语句因为崩溃或其他原因无法执行,那么所有的语句都不会执行。也就是说,事务内的语句,要么全部执行成功,要么全部执行失败。

银行应用是解释事务必要性的一个经典例子。假设一个银行的数据库有两张表:支票(checking)表和储蓄(savings)表。现在要从Jane的支票账户转移200美元到她的储蓄账户,那么需要至少3个步骤:

    1.检查支票账户余额高于200美元。 

    2.从支票账户余额中减去200美元。

    3.在储蓄账户余额中增加200美元。

上述三个操作必须打包在一个事务中,任何一个步骤失败,则必须回滚所有步骤。

除非系统通过严格的ACID测试,否则空谈事务的概念是不够的。ACID表示原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)。一个运行良好的事务处理系统,必须具备这些标准特征。

原子性:对于一个事务来说,要么全部提交成功,要么全部失败回滚,不可能执行其中的一部分,这就是事务的原子性。

一致性:数据库总是从一个一致性状态转换到另一个一致性的状态。如果银行转账一半网络中断了,也不用担心钱会消失,因为数据库处于一致性状态。

隔离性:通常一个事务所做的修改在最终提交以前,对其他事务都是不可见的。

持久性:一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。

二、并发事务的四个问题

丢失更新:指的是并发事务A,B同时读取同一个数据,并都执行写操作,那么B的写操作可能覆盖A的写操作。

事务A 事务B
读取x=100 读取x=100
x=x+100 x=x+200
事务结束x=200 事务结束x=300
  最后x=300,覆盖了A的更新

脏读:指的是并发事务A执行写操作,并发事务B执行读操作,那么B可能读到A未提交的内容。

事务A 事务B
读取x=100  
x=x+100 读取事务A写的x=200
事务回滚x=100  
事务结束x=100  

不可重复读:指的是并发事务A执行写操作,并发事务B在自身没有更新数据的情况下,多次读到了不同的结果(就相当于事务B之间插入了一个事务A修改了数据)。

事务A 事务B
读取x=100 读取x=100
x=x+100  
事务结束x=200 读取x=200

幻读:指的是并发事务A插入或删除数据,导致并发事务B在自身没有插入或删除的情况下,多次读到了不同的数据库行数(就相当于事务B之间插入了一个事务A增删了数据行)。

事务A 事务B
记录数为100 记录数为100
insert一条记录  
事务结束,记录数为101 记录数为101

三、事务的四大隔离级别

前面提到“通常来说,一个事务在提交前的任何修改,对其他事务都是不可见的”,但实际中隔离性更为复杂。在SQL标准中定义了四种隔离级别,每一级别都规定了一个事务中所做的修改,哪些在事务内和事务间是可见的,哪些是不可见的。

未提交读(read uncommitted):事务中的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,也称为脏读。

提交读(read committed):提交读满足前面提到的隔离性的简单定义,一个事务开始时,只能看见已经提交事务所做的修改。换句话说,一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。这个级别也叫不可重复读,因为两次执行相同的查询,可能会得到不一样的结果。

可重复读(repeatable read):该级别保证了在同一个事务中多次读取同样记录的结果是一致的。但依旧无法解决幻读的问题,为此InnoDB存储引擎通过MVCC(多版本并发控制)解决了这一问题。

可串行化(serialzable):它通过强制事务串行执行,避免前面提到的所有问题,但基本在并发情况下不会被使用。
四、实现四大隔离级别的四级封锁协议

一级封锁协议(对应未提交读):事务T在修改数据R之前,必须要加上X锁,可以避免丢失更新的问题。

二级封锁协对应:事务T在修改数据R之前,必须要加上X锁;事务T在读取数据R之前,必须要加上S锁,读完后释放S锁。这样就避免了读脏数据。

三级封锁协对应可重复:事务T在修改数据R之前,必须要加上X锁;事务T在读取数据R之前,必须要加上S锁,事务结束后才释放。这样在二级封锁协议的基础上避免不可重复读的问题。

最强封锁协议(对应可串行化):四级封锁协议是对三级封锁协议的增强,其实现机制也最为简单,直接对事务中所读取或者更改的数据所在的表加表锁,也就是说,其他事务不能读写该表中的任何数据。

为什么一级封锁协议不能禁止脏读:在事务T修改数据R之前,需要加排它锁,此时其他事务不能申请共享锁或排它锁,但可以直接通过基本的select来读取数据,不用加锁。

 

以上参考 :微信 猿媛之家 数据库四大隔离级别实现原理 文章

posted @ 2021-12-07 10:56  远方的风景  阅读(73)  评论(0)    收藏  举报