zoukankan      html  css  js  c++  java
  • mysql 开发进阶篇系列 10 锁问题 (使用“索引或间隙锁”的锁冲突)

    1.使用“相同索引键值”的冲突

      由于mysql 的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但如果是使用相同的索引键,是会出现锁冲突的。设计时要注意
      例如:city表city_id字段有索引,Cityname字段没有索引:

    会话1

    会话2

    SET autocommit=0;

    SET autocommit=0;

    SELECT * FROM city WHERE city_id=14 AND Cityname='深圳' FOR UPDATE;

    city_id      country_id        cityname CityCode

    14     2       深圳         001

     

     

    会话2与会话1访问的是不同的记录,但是因为使用了相同的索引值,所以需要等待锁

    SELECT * FROM city WHERE city_id=14 AND Cityname='长沙' FOR UPDATE;

    等待...

     

    2.使用不同索引键值但是同一行的冲突 

      当表有多个索引时候,不同的事务可以使用不同的索引锁定不同的行,无论什么索引,innodb都会使用行锁来对数据加锁。
      例如:city表city_id字段是主键索引,CityCode字段是普通索引。 where city_id=14 与where  CityCode='001' 是查询同一行。

    会话1

    会话2

    SET autocommit=0;

    SET autocommit=0;

    SELECT * FROM city WHERE city_id=14  FOR UPDATE;

    city_id      country_id        cityname CityCode

    14     2       深圳         001

     

     

    该记录没有被索引,所以可以获得锁

    SELECT * FROM city WHERE  CityCode='002' FOR UPDATE;

    city_id      country_id        cityname CityCode

    15     2       长沙         002

     

    由于该记录被会话1锁定,所以需要等待

    SELECT * FROM city WHERE  CityCode='001' FOR UPDATE;

    等待...

    3. 创建了索引,但使用的是表锁
      在前面章节说过,创建了索引但不走索引的情况,这种情况下innodb将使用表锁,而不是行锁,因些分析锁冲突时,还需检查sql的执行计划,以确认是否真正使用了索引。

     

    4. 间隙锁(next-key) 并发下要重点考虑

             当我们用范围条件而不是相等条件检索数据,并请求共享或排它锁时,innodb会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录就叫做"间隙锁"  比如city表数据分布如下:

     

       如果查询使用如下sql
      select * from city where city_id>100 for update;

      这就是一个范围条件的检索, innodb不但会对符合条件的101的记录加锁,也会对city_id大于101(虽然记录并不存在)的"间隙"加锁。使用间隙锁的目的是为了防止幻读,以满足相关的隔离级别。关于幻读查看"sql 开发进阶篇系列 6 锁问题(事务与隔离级别介绍)"
    很明显,在使用范围条件的检索记录时, 会阻塞符合条件范围内键值的并发插入,往往造成严重的锁等待。在实现业务中尽量使用相等条件来检索数据。还需注意如查使用相等条件检索的数据不存在时,也会加间隙锁。
      为了防止幻读,mysql隔离级别必须是REPEATABLE-READ和Serializable。REPEATABLE-READ也是默认的隔离级别。

    会话1

    会话2

    SELECT @@tx_isolation

    @@tx_isolation

    REPEATABLE-READ

    SELECT @@tx_isolation

    @@tx_isolation

    REPEATABLE-READ

    SET autocommit=0;

    SET autocommit=0;

    -- 当前会话对不存在的记录加 for update;

    SELECT * FROM city WHERE city_id=102 FOR UPDATE;

    如果这里插入的值>=102就会出现阻塞

    INSERT INTO city VALUES(200,2,'江门','005')

    错误代码: 1205

    Lock wait timeout exceeded; try restarting transaction

    ROLLBACK;

    INSERT INTO city VALUES(200,2,'江门','005')

    共 1 行受到影响

  • 相关阅读:
    代理服务器的原理及用法
    [Web前端] 给li设置float浮动属性之后,无法撑开外层ul的问题。
    [Web 前端] react-router4-0中文文档
    [Web 前端] inline-block元素设置overflow:hidden属性导致相邻行内元素向下偏移
    [Web 前端] React Js img 图片显示默认 占位符
    [Web 前端] React高级教程(es6)——(2)对于Refs最新变动的理解
    [Web 前端] 你不知道的 React Router 4
    [Web 前端] React-router4简约教程
    [Web 前端] React Router v4 入坑指南
    [Web 前端] 前端频道之团队维护、聚合、订阅
  • 原文地址:https://www.cnblogs.com/MrHSR/p/9390350.html
Copyright © 2011-2022 走看看