美文网首页
并发、锁、事务隔离级别

并发、锁、事务隔离级别

作者: 漂泊的胡萝卜 | 来源:发表于2018-10-23 11:24 被阅读0次

    最近面试发现自己对Mysql的事务了解有点粗糙,正好看到沈剑大神的博客解答了我的疑惑,决定梳理一下,整理出自己的理解。
    事务的隔离级别是一致性和并发性的折衷,而InnoDB通过锁和MVCC来实现,以避免脏读、不可重复读、幻读。

    一.Mysql(InnoDB)的七种锁:
    (1)共享/排它锁(Shared and eXclusive Locks,S锁和X锁)
    共享锁(lock in share mode),共享锁之间是可以并行的,与排它锁之间是互斥的。排它锁(for update)与2种锁都是互斥的。
    锁有2个操作,获取和释放,显式使用锁语句获取这两个锁,提交事务释放锁,也就是说在autocommit=1的情况下,获取锁后会马上释放。
    并不是所有情况下,都需要显式定义锁,InnoDB的事务实际上是通过锁来实现一致性的,在某些事务级别下,Mysql会隐式的自动加锁。

    (2)意向锁(Intention Locks)
    意向锁是表级锁,意向锁就是在声明锁前先加一个意向,它也分共享(IS)、互斥(IX)两种。意向锁之间都是不互斥的,但是与互斥共享锁之间,只有IS和S是兼容的,其他都是互斥的。
    InnoDB中表锁和行锁共存,这就是依赖意向锁来实现的,试想,如果对一个表加行锁,之后又有一个连接对该表加表锁,这时首先要去检查该表是否有表锁,然后再检查表中的每一行是否有行锁,这就发生了遍历。如果通过意向锁来实现呢?首先查看是否有表锁,再查看表上是否有意向锁,如果有意向锁,再看意向锁是否和自己申请的锁互斥,Bingo,问题解决。

    (3)记录锁(Record Locks)
    对索引记录进行加锁,未走到索引则会变为表锁。

    (4)间隙锁(Gap Locks)
    锁住索引记录的间隔,若事务隔离级别为读提交(Read Commit,RC),间隙锁会自动失效。

    (5)临键锁(Next-key Locks)
    记录锁与间隙锁的组合,它封锁范围,也封锁记录。若事务隔离级别为读提交(Read Commit,RC),临间锁会自动失效。

    记录锁,间隙锁,临键锁都是针对索引进行锁定,若没有走到索引则会变为表锁。所以,这里我们看到InnoDB的索引不仅影响了其性能,还对锁的互斥产生影响。

    (6)插入意向锁(Insert Intention Locks)
    插入意向锁是间隙锁的一种(专门实施在索引上,只针对插入操作),InnoDB使用强互斥锁实现一致性,使用插入意向锁提高插入并发。

    (7)自增锁(Auto-inc Locks)
    有三种模式,配置innodb_autoinc_lock_mode决定其级别(不同级别性能不同)。主要解决id的自增问题,表级锁,对性能会有一定影响。

    二.MVCC
    Mysql能实现较高的并非主要是因为其MVCC机制,其核心原理是:
    (1)写任务发生时,将数据克隆一份,以版本号区分;
    (2)写任务操作克隆的数据,直至提交;
    (3)并发读任务可以读取旧版本的数据,以不至于阻塞。
    Mysql MVCC旧版本的数据存储在undo日志(回滚段)中,以减少对原有体系的冲击。
    Mysql InnoDB中未加锁的读是快照读,即通过MVCC机制实现,该机制提高了InnoDB的性能。
    (MVCC通过为数据提供多个版本,使数据的读写互不冲突,支持RC、RR隔离级别,在RC级别下,快照读每次读取到最新的提交数据,而RR级别下,快照读每次读取到的是第一次读操作之前提交的数据)。

    三.事务与锁
    事务的隔离级别是通过锁来实现的(RC、RR级别下有MVCC支持):
    (1)读未提交:select不加锁,可能出现脏读;
    (2)读已提交:普通select快照读,加锁的select、update和delete会使用记录锁(重复键检查和外键约束检查条件下会锁区间);
    (3)可重复读:普通select快照读,加锁的select、update和delete会使用记录锁、或者间隙锁、临键锁,防止读到幻影记录;
    (4)串行化:select隐式转换为in share mode,会被update和delete互斥。

    附录:
    MVCC在一定程度上解决了幻读的问题,然而并没有完全解决。
    MySQL InnoDB的可重复读并不保证避免幻读,需要应用使用加锁读来保证。而这个加锁度使用到的机制就是next-key locks。
    两种RR级别下的幻读:
    (1)两个连接中的事务:一个事务增加一个记录,另一个事务先查询,后根据该唯一键增加,会阻塞或报错;
    (2)两个连接中的事务:一个事务增加一个记录,另一个事务先查询,后更新该记录,再查询,能查到最新记录;
    可以通过读的时候加锁,解决该问题。

    (InnoDB用的最多的隔离级别是RC,默认隔离级别是RC)。

    (这篇文章内容主要出自沈剑的博客,归纳下来,让自己印象更深刻些)
    参考文献:
    https://mp.weixin.qq.com/s/wGOxro3uShp2q5w97azx5A(沈剑博文聚合)
    https://blog.csdn.net/wufaliang003/article/details/81905661(Mysql七种锁)
    https://blog.csdn.net/gao_yu_long/article/details/73739559(MVCC)
    https://www.jianshu.com/p/e937830bc2de(意向锁)
    https://www.cnblogs.com/JiangLe/p/6362770.html(自增锁,innodb_autoinc_lock_mode)
    http://blog.sina.com.cn/s/blog_499740cb0100ugs7.html(RR级别下的幻读问题)

    相关文章

      网友评论

          本文标题:并发、锁、事务隔离级别

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