zoukankan      html  css  js  c++  java
  • MySQL如何使用锁解决幻读

    MySQLREPEATABLE READ级别解决了幻读问题,解决方案有两种,一种是MVCC版本控制链,具体可以参考这个,MVCC 多版本控制链,还有就是通过加锁的方式。这篇文章简要介绍一下MySQL是如何通过加锁来解决幻读问题的。

    准备工作

    还是一样,先创建一张表,如下所示:

    CREATE TABLE hero (
        number INT,
        name VARCHAR(100),
        country varchar(100),
        PRIMARY KEY (number)
    ) Engine=InnoDB CHARSET=utf8;
    

    然后插入如下数据:

    INSERT INTO hero VALUES
        (1, '刘备', '蜀'),
        (3, '诸葛亮', '蜀'),
        (8, '曹操', '魏'),
        (15, '荀彧', '魏'),
        (20, '孙权', '吴');
    

    此时MySQL中的示意图简化如下所示:

    前置知识

    MySQL行锁分为两种,共享锁S,以及独占锁X。当使用select * from ...或者是select * from ... in share mode这两种语法时,会对进行搜索的行记录加上S锁。当使用select * from ... for update这个语法时就会对记录加X锁。

    当一个事务获取了一条记录的S锁,其他事务可以获取该记录的S锁,但不可以获取X锁;当一个事务获取了一条记录的X锁,其他事务不可以继续获取该条记录的X锁或者S锁。

    分析

    Record Locks

    当开启一个事务,使用select * from语句时,InnoDB会对搜索的记录进行加锁,官方名称为LOCK_REC_NOT_GAP,具体是S锁还是X锁,具体视select语句而定。例如现在查找number值为8的记录,

    select * from hero where number=8;
    

    此时示意图如下所示:

    Gap Locks

    接下来就涉及到了MySQL如何利用加锁来解决REPEATABLE READ级别解决幻读了。上面说了,当使用select 语句查询时,InnoDB会对记录加记录锁,但这就出现一个问题了,这个事务执行第一次查询时,另一个事务要插入的数据此时还不存在,这个事务就无法对这些幻影记录加上记录锁啊,那该怎么办呢?为了解决这个问题,InnoDB引入了一种新的锁机制,称之为LOCK_GAP间隙锁。例如,我们可以在number值为8的那条记录上添加一个gap锁,如下所示:

    当一条记录被加上gap锁时,就意味着不允许其他事务在number值8的前面的间隙,即(3,8)这个区间内插入新的记录。比如说,现在有另一个事务想要插入一条记录,(4,"张飞",“蜀”)。此时,定位到该条记录的下一条记录的number值为8,而这条记录上又有一个gap锁,因此这个插入操作就会被阻塞住,直到拥有这个gap锁的事务提交之后,number列的值在(3,8)中的新记录才能被插入。

    gap锁的主要作用就是为了防止插入幻影记录,如果你对一条记录加了gap锁,并不会限制其他事务对这条记录继续加记录锁或者gap锁。

    Next-Key Locks

    当我们既想锁住某条记录,又想阻止其他事务在该记录前边的间隙插入新纪录,此时该怎么办呢?这个时候,InnoDB又出现了一个新的锁结构,LOCK_ORDINARY,也被称之为next-key锁,临键锁。它其实是record锁和gap锁的结合体。如下所示,给number值为8的记录加一个next-key锁。

    总结

    • InnoDB中存在着不同的锁,当使用select语句查询某条记录时,InnoDB会对该记录加记录锁,即record锁;
    • 当一个事务对某条记录加上gap锁时,另一个事务此时向这条记录前面间隙插入新记录的操作将会被阻塞;
    • next-key锁,又称为临键锁,是记录锁和间隙锁的结合体。既锁住某条记录,又会将该记录前面的间隙一同锁住,解决了MySQLREPEATABLE READ级别下的幻读问题。
  • 相关阅读:
    一个随机数生成函数
    HTTP Post请求过程详解
    md5加密算法c语言版
    android popupwindow 自定义视图
    android 获取顶部状态栏的高度
    android 显示和隐藏输入框
    android tablayout + recycleview 简单使用
    jetpack paging使用
    android 自定义控件 属性配置
    vueLazyload 图片懒加载
  • 原文地址:https://www.cnblogs.com/reecelin/p/13469969.html
Copyright © 2011-2022 走看看