美文网首页
数据库隔离级别和实现原理

数据库隔离级别和实现原理

作者: 万物皆有序和公式 | 来源:发表于2021-05-21 16:00 被阅读0次

一、数据库事务正确的四个要素(ACID)[1]

      原子性(Atomicity):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做,不能只做一部分;

        一致性(Consistency):在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是处于正确的状态,即数据完整性约束没有被破坏;比如我们做银行转账的相关业务,A转账给B,要求A转的钱B一定要收到。如果A转了钱而B没有收到,那么数据库数据的一致性就得不到保障,在做高并发业务时要注意合理的设计。

    隔离性(Isolation):并发事务执行之间无影响,在一个事务内部的操作对其他事务是不产生影响,这需要事务隔离级别来指定隔离性;

      持久性(Durability):事务一旦执行成功,它对数据库的数据的改变必须是永久的,不会因各种异常导致数据不一致或丢失。

二、并行事务的四个问题

先理解锁的概念:https://www.cnblogs.com/Jomini/p/13219722.html

2.1、丢失更新

     别的事务读到相同的东西,各自写,自己的写被覆盖了。

     两个事务同时更新一行数据,最后一个事务的更新会覆盖掉第一个事务的更新,从而导致第一个事务更新的数据丢失,后果比较严重。一般是由于没加锁的原因造成的。

    解决方式 :使用数据库锁机制

(详细: [https://www.cnblogs.com/doucheyard/p/5662171.html](https://links.jianshu.com/go?to=https%3A%2F%2Fwww.cnblogs.com%2Fdoucheyard%2Fp%2F5662171.html) )

2.2、脏读(Dirty reads)

    读到别的事务未提交的数据

    一个事务A读取到了另一个事务B还没有提交的数据,并在此基础上进行操作。如果B事务rollback,那么A事务所读取到的数据就是不正确的,会带来问题。

2.3、不可重复读(Non-repeatable reads)

      两次读之间有别的事务修改

     在同一事务范围内读取两次相同的数据,所返回的结果不同。比如事务B第一次读数据后,事务A更新数据并commit,那么事务B第二次读取的数据就与第一次是不一样的。

2.4、 幻读(Phantom reads)

     两次读之间有别的事务增删

     一个事务A读取到了另一个事务B新提交的数据。比如,事务A对一个表中所有行的数据按照某规则进行修改(整表操作),同时,事务B向表中插入了一行原始数据,那么后面事务A再对表进行操作时,会发现表中居然还有一行数据没有被修改。

2.5、注意:不可重复读和幻读的区别是,不可重复读对应的表的操作是更改(UPDATE),而幻读对应的表的操作是插入(INSERT),两种的应对策略不一样。对于不可重复读,只需要采用行级锁防止该记录被更新即可,而对于幻读必须加个表级锁,防止在表中插入数据。有关锁的问题,下面会讨论。

三、解决方式

   SQL定义了下面的4个等级的事务隔离级别:

3.1、未提交读(READ UNCOMMITTED )

      最低隔离级别,一个事务能读取到别的事务未提交的更新数据,很不安全,可能出现丢失更新、脏读、不可重复读、幻读;

      原理:

    (1)事务对当前被读取的数据不加锁;

             事务1读取某行记录时,事务2也能对这行记录进行读取、更新;当事务2对该记录进行更新时,事务1再次读取该记录,能读到事务2对该记录的修改版本,即使该修改尚未被提交。

    (2)事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加 行级共享锁,直到事务结束才释放。

              事务1更新某行记录时,事务2不能对这行记录做更新,直到事务1结束。

3.2、提交读(READ COMMITTED)

     一个事务能读取到别的事务提交的更新数据,不能看到未提交的更新数据,不会出现 丢失更新、脏读,但可能出现不可重复读、幻读;

     原理:

     (1)事务对当前被读取的数据加行级共享锁(当读到时才加锁),一旦读完该行,立即释放该行级共享锁;

        【*注意是:一旦读完该行,立即释放该共享锁(注意是读完立即释放),所以第二次读的数据将会不同,即导致 “不可重复读” 的问题】*

            事务1读取某行记录时,事务2也能对这行记录进行读取、更新;当事务2对该记录进行更新时,事务1再次读取该记录,读到的只能是事务2对其更新前的版本,要不就是事务2提交后的版本。

     (2)事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加行级排他锁,直到事务结束才释放。

              事务1更新某行记录时,事务2不能对这行记录做更新,直到事务1结束。

3.3、可重复读(REPEATABLE READ)

     保证同一事务中先后执行的多次查询将返回同一结果,不受其他事务影响,不可能出现丢失更新、脏读、不可重复读,但可能出现幻读;

       原理: 

       (1) 事务在读取某数据的瞬间(就是开始读取的瞬间),必须先对其加 行级共享锁,直到事务结束才释放;

             事务1读取某行记录时,事务2能对该表读取,但不能修改,事务1再次读取该记录,读到的仍然是第一次读取的那个版本。

        【*注意:和 “提交读” 的读操作不同的是,这里读加的共享锁 是整个事务都加了,而不是读完就解锁;】*

       (2) 事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加 行级排他锁,直到事务结束才释放

              事务1更新某行记录时,事务2不能对这行记录做更新,直到事务1结束。

         问题:因为事务1读取和修改的的时候只是加了行级别锁, 所以其他事务可以对该表插入数据,会导致幻读 

3.4、序列化(SERIALIZABLE)

    最高隔离级别,不允许事务并发执行,而必须串行化执行,最安全,不可能出现更新、脏读、不可重复读、幻读,但是效率最低。

   隔离级别越高,数据库事务并发执行性能越差,能处理的操作越少。所以一般地,推荐使用REPEATABLE READ级别保证数据的读一致性。对于幻读的问题,可以通过加锁来防止。 

     原理:

   (1)事务在读取数据时,必须先对其加 表级共享锁 ,直到事务结束才释放;

             事务1正在读取A表中的记录时,则事务2也能读取A表,但不能对A表做更新、新增、删除,直到事务1结束。

   (2)事务在更新数据时,必须先对其加 表级排他锁 ,直到事务结束才释放。

            事务1正在更新A表中的记录时,则事务2不能读取A表的任意记录,更不可能对A表做更新、新增、删除,直到事务1结束。
image.png

相关文章

网友评论

      本文标题:数据库隔离级别和实现原理

      本文链接:https://www.haomeiwen.com/subject/gwvwjltx.html