事务的级别

169 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情

事务的四种隔离级别:

    1. 读未提交(Read uncommitted):

    • 原理:如果是一个读事务,则允许其他事务读写,如果一个事务已经开始写数据,则另外一个事务不允许同时进行写操作,但允许其他事务同时读此行数据。

    • 缺陷(脏读):事务B读取到了事务A还未提交的数据。

      • 1.数据X=1;
      • 2.事务A开始对数据X进行写,修改x=2;还没提交;根据上面的原理,此时只是不允许其他事务进行写,还可以读。
      • 3.事务B开始读取数据X,读取到数据X为1。
      • 4.此时事务A提交数据,X=2,但是事务B读到的数据却是X=1。
  • 2.读提交(Read committed):

    • 原理:如果是一个读事务,则允许其他事务读写,如果是写事务将会禁止其他事务访问该行数据。

    • 缺陷(不可重复读):事务A事先读取了数据,事务B紧接着更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。

      • 1.数据X=1;
      • 2.事务A开始读取数据X,读取到数据X为1,此时事务A还未提交;
      • 3.事务B开始对数据X进行写,修改x=2;事务B提交事务,事务A还未提交。
      • 4.此时事务A中后续操作还需要继续用到X,再次读取数据X,但是此时数据X变成了2,在事务A中两次读取的数据不一致。
  • 3.可重复读取(Repeatable read)

    • 原理:读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务(包括了读写)。

    • 缺陷(幻读):

      • 1.事务A读取与搜索条件相匹配的若干行,此时用的条件是具体的,比如用的等号=;事务A还未提交;(注意是行锁,此时用的是行锁中的记录锁,只锁住了具体的某些行,没有锁住某个范围)
      • 2.事务B以插入或删除行等方式来修改事务A的结果集(插入的数据不是事务A锁住的某些具体行),然后事务B提交;此时事务A还未提交。
      • 3.在回到事务A中,感觉多了一些还未修改的数据行,就好像发生了幻觉一样。
    • 再来一个百度百科例子:

      • 幻读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还存在没有修改的数据行,就好象发生了幻觉一样.一般解决幻读的方法是增加范围锁RangeS,锁定检索范围为只读,这样就避免了幻读。
    • 两种方案解决幻读:

      • 1.最高隔离级别SERIALIZABLE_READ可以保证不出现幻读的问题。

      • 2.针对当前读,RR(Repeatable read)隔离级别保证对读取到的记录加锁 (记录锁),同时保证对读取的范围加锁,新的满足查询条件的记录不能够插入 (间隙锁) ,不存在幻读现象。(记录锁+间隙锁)

        • 解析:

          需要用到间隙锁,间隙锁至少在隔离级别为可重复读取(Repeatable read)或以上才会有,当查询的条件从等号=变某个范围时(betten或者大于>小于<号),行锁的具体的锁实现为间隙锁。

          也就是说这种情况要求的是插入的记录,在查询的条件之中,因为此时是RR(Repeatable read),给读取的记录加上了记录锁,只要是满足条件的,(就像上面讲行锁的时候,行锁的锁范围可分为记录锁、间隙锁和临键锁,这个地方需要用到间隙锁,具体看上面的例子),比如在1到3之间没查到数据,那我也把(1,3]之间的数据给锁住了,如果在要插入记录2或者是记录3是不可能的,因为记录锁已经锁住了这个范围。

  • 4.可串行化读(Serializable)

    • 原理:提供严格的事务隔离,它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行,如果仅仅通过“行级锁”是无法实现序列化的,必须通过其他机制保证新插入的数据不会被执行查询操作的事务访问到。
    • 利弊:序列化是最高的事务隔离级别,同时代价也是最高的,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻读。

\