zoukankan      html  css  js  c++  java
  • mysql间隙锁

    什么是间隙锁(gap lock)?

      间隙锁是一个在索引记录之间的间隙上的锁。

    间隙锁的作用?  

      保证某个间隙内的数据在锁定情况下不会发生任何变化。比如我mysql默认隔离级别下的可重复读(RR)。

      当使用唯一索引来搜索唯一行的语句时,不需要间隙锁定。如下面语句的id列有唯一索引,此时只会对id值为10的行使用记录锁。

        select * from t where id = 10 for update;// 注意:普通查询是快照读,不需要加锁
      如果,上面语句中id列没有建立索引或者是非唯一索引时,则语句会产生间隙锁。

      如果,搜索条件里有多个查询条件(即使每个列都有唯一索引),也是会有间隙锁的。

      需要注意的是,当id列上没有索引时,SQL会走聚簇索引的全表扫描进行过滤,由于过滤是在MySQL Server层面进行的。因此每条记录(无论是否满足条件)都会被加上X锁。但是,为了效率考量,MySQL做了优化,对于不满足条件的记录,会在判断后放                锁,最终持有的,是满足条件的记录上的锁。但是不满足条件的记录上的加锁/放锁动作是不会省略的。所以在没有索引时,不满足条件的数据行会有加锁又放锁的耗时过程。

    间隙的范围?

      根据检索条件向下寻找最靠近检索条件的记录值A作为左区间,向上寻找最靠近检索条件的记录值B作为右区间,即锁定的间隙为(A,B] 左开右闭

    通过上面的描述,感觉很抽象?

      没关系,下面我们来通过具体的实验来说明gap锁。再次强调(当使用唯一索引来搜索唯一行的语句时,不需要间隙锁定

      我们先创建一张数据表: 

    MariaDB [locktest]> create table gaplockt(
    -> id int not null,
    -> name varchar(255) not null primary key,
    -> key `id_index` (`id`)
    -> );

      在向表中插入一些数据:

    MariaDB [locktest]> insert into gaplockt values(1,'panchao'),(5,'songzuer'),(10,
    'yangmi');

      现在我们的表情况是这样的:

    MariaDB [locktest]> select * from gaplockt;
    +----+----------+
    | id | name |
    +----+----------+
    | 1 | panchao |
    | 5 | songzuer |
    | 10 | yangmi |
    +----+----------+

      接下来我们设置autocommit = 0;

    MariaDB [locktest]> set autocommit = 0;

    MariaDB [locktest]> select @@autocommit;
    +--------------+
    | @@autocommit |
    +--------------+
    | 0 |
    +--------------+

      现在我们的准备工作已经做完了,我们再事物A中给记录添加一个写锁:

    MariaDB [locktest]> select * from gaplockt where id = 5 for update;
    +----+----------+
    | id | name |
    +----+----------+
    | 5 | songzuer |
    +----+----------+

      由于id不是唯一索引,表上加上相应的gap锁。如下图:

      以上语句会给表加上的gap锁包括(gap2和gap3),也就是1~5U5~10,特别注意这个区间为左开右闭区间(1,10],没理解没关系,我们接下来通过实验来验证。

      实验1、

      MariaDB [locktest]> insert into gaplockt values(6,'jingruyang');

      ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 

      MariaDB [locktest]> insert into gaplockt values(4,'jingruyang');
      ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

      MariaDB [locktest]> insert into gaplockt values(1,'jingruyang');
      Query OK, 1 row affected (0.00 sec)

      MariaDB [locktest]> insert into gaplockt values(10,'jingruyang10');

      ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

      通过以上实验,我们可以看到当id = 1的时候,我们是能添加数据的,但是当id = 10的时候我们是不能添加数据的,事实证明,我们的这个gap锁区间为(1,10]

      实验2、

      接下来我们来讨论gap1和gap4的问题。

      当我们执行以下语句的时候,或收获gap4锁。

      MariaDB [locktest]> select * from gaplockt where id = 100 for update;

      那么gap4锁的范围是多少呢? 是(10,100]吗?

      直接告诉你们答案,不是,它的范围是(10,+∞),下面我们通过实验来验证。

      MariaDB [locktest]> insert into gaplockt values(99,'jingruyang99');
      ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
      MariaDB [locktest]> insert into gaplockt values(100,'jingruyang100');
      ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
      MariaDB [locktest]> insert into gaplockt values(1000,'jingruyang1000');
      ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

      可以看到id=99   id= 100  id=1000  都是上了锁的,所以gap4的区间为(10,+∞)

      我们再来讨论gap1

      执行以下语句获取gap1

      MariaDB [locktest]> select * from gaplockt where id = -100 for update;

      gap1的区间我直接告诉大家,(-∞,1)

      下面我们通过实验证明。

      MariaDB [locktest]> insert into gaplockt values(-99,'jingruyang99');
      ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
      MariaDB [locktest]> insert into gaplockt values(-100,'jingruyang99');
      ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
      MariaDB [locktest]> insert into gaplockt values(-10000,'jingruyang99');
      ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

      看到上面的结果,就不用我多说什么了吧。

    以下是两个比较有参考价值的链接,有兴趣的朋友可以看一下。

      Mysql中的GAP锁(间隙锁)

      MySQL的innoDB锁机制以及死锁处理

  • 相关阅读:
    Spring实现AOP的4种方式(转)
    【转】一个不错的eclipse反编译插件
    spring配置事务
    使用XFire+Spring构建Web Service(一)——helloWorld篇
    WebService到底是什么?(转)
    ContextLoaderListener作用详解(转)
    SVN检出资源文件
    ExtJS4.2学习(21)动态菜单与表格数据展示操作总结篇2
    WP8_当滚动到滚动条的70%时,自动加载数据效果实现
    WP8__从windowsphone app store 中根据app id获取应用的相关信息(下载网址及图片id等)
  • 原文地址:https://www.cnblogs.com/573734817pc/p/11359603.html
Copyright © 2011-2022 走看看