http://hedengcheng.com/?p=771

mysql lock in share mode 和 select for update

2016年09月28日 10:23:32

阅读数:2820

工作需要,接触到以下两个mysql sql语法:

  1. select lock in share mode
  2. select for update
  • 1
  • 2

从官网上查找到对应的章节,属于Locking Reads里面的内容,具体链接如下:

locking-reads

根据官网介绍,这两个语句是在事务内起作用的,所涉及的概念是行锁。它们能够保证当前session事务所锁定的行不会被其他session所修改(这里的修改指更新或者删除)。两个语句不同的是,一个是加了共享锁而另外一个是加了排它锁。可以这么理解,共享锁允许其他事务加共享锁读取,但是,不允许其他事务去做修改,或者加排它锁。而排它锁显得更加严格,不允许其他事务加共享锁或者排它锁,更加不允许其他事务修改加锁的行。

说到这里,行锁有什么用呢?设想下面这种场景:

1) 读取一行数据 
2) 根据读取到的数据去更新其他数据

假设在1)和2)之间,有个其他的user session刚好修改了你读取的那行数据,那么你下面的更新就有可能会出错!因为关联的数据产生了变化!

行锁就能够保证不会出现上面所说的这种尴尬的场景。

实践了一把,下面记录它们的用处:

测试用的表结构并插入一行记录:

  1. use test;
  2. create table tb_test (
  3. id int primary key,
  4. col1 varchar(20)
  5. ) engine = innodb default character set = 'utf8';
  6. insert into tb_test(id, col1) values(1, 'AAA');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

1. select lock in share mode

1.1 使用示例

session 1:

  1. set autocommit = 0;
  2. select * from tb_test where id = 1 lock in share mode;
  • 1
  • 2

open session 2:

  1. update tb_test set col1 = 'BBB' where id = 1;
  • 1

这个时候可以观察到session2处于blocking状态….

直到 
session 1:

  1. commit;
  • 1

这个时候session2更新成功了。

这里也就验证了lock in share mode可以在事务中保证锁定的行不被其他session所更改。

1.2 注意死锁

使用lock in share mode具有很高的风险,看下面的案例:

session 1:

  1. set autocommit = 0;
  2. select * from tb_test where id = 1 lock in share mode;
  • 1
  • 2

open session2:

  1. set autocommit = 0;
  2. select * from tb_test where id = 1 lock in share mode;
  • 1
  • 2

这个时候两个session同时持有id = 1这行数据的共享锁。这个时候我们在session 1里面执行update操作:

session 1:

  1. update tb_test set col1 = 'AAA' where id = 1;
  • 1

卡住了!!!! ????

这个时候session1必须等待session2退出事务或者等待直到锁超时:

锁超时的情况:

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

如果我们在session 2里面执行:

session2:

  1. update tb_test set col1 = 'BBB' where id = 1;
  2. ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
  • 1
  • 2
  • 3

这个时候mysql检测到会发生死锁,会中断当前事务该语句的执行,重新开启一个新的事务(应该就是相当于session2先退出事务,然后再开启一个事务吧)。

这个时候session1可以更新成功了。

上面的例子可以看出使用lock in share mode比较危险,很可能因为其他session同时加了这种锁,导致当前session无法进行更新,进而阻塞住。

2. select for update

select for update加的是排它锁,所以没有上面lock in share mode所产生的死锁,因为一个session加了这种锁,其他session除了读取操作,其他操作都不能进行,如更改操作,或者加锁,共享锁和排它锁都不可以。

2.1 使用示例

下面演示一下用法:

session 1:

  1. set autocommit = 0;
  2. select * from tb_test where id = 1 for update;
  • 1
  • 2

open session 2:

  1. update tb_test set col1 = 'BBB' where id = 1;
  • 1

这个时候session 2处于blocking状态

我们手动kill掉session 2, 按Ctrl + C

然后执行:

session 2:

  1. set autocommit = 0;
  2. select * from tb_test where id = 1 for update;
  • 1
  • 2

还是blocking状态,证明其他session的事务不能对已经加了排它锁(for update)的行再加排它锁。

kill掉,再来

session 2:

  1. set autocommit = 0;
  2. select * from tb_test where id = 1 lock in share mode;
  • 1
  • 2

还是blocking状态,证明其他session的事务不能对已经加了排它锁(for update)的行再加共享锁(lock in share mode)。

当然,如果使用select for update的时候,如果锁定当前行的事务一直不退出,将会导致其他进行这个行更改操作的session一直阻塞。(没有试是否有超时的情况)

2. 总结

因此,无论在使用select lock in share mode 或者 select for update,都应该尽快释放锁。

确实是这样的,LOCK IN SHARE MODE是读锁(只是不让别人写),FOR UPDATE是写锁(还不让别人加读锁),读锁升级成写锁是可能产生死锁的(但写锁降级成读锁则不会,我还真不知道MySQL如何对锁降级),所以程序中需要考虑超时的问题(或者重试或者放弃)。

所以大部分情况下都如果SELECT后接下来会有UPDATE动作的话,一般会用FOR UPDATE而不是LOCK IN SHARE MODE。

MySQL 加锁处理分析 ---非常牛逼的更多相关文章

  1. MySQL 加锁处理分析 转

    MySQL 加锁处理分析  转 http://hedengcheng.com/?p=771 十二 13th, 2013 发表评论 | Trackback   1    背景    1 1.1    M ...

  2. 转载-MySQL 加锁处理分析

    MySQL 加锁处理分析 发表于 2013 年 12 月 13 日 由 hedengcheng 1    背景    1 1.1    MVCC:Snapshot Read vs Current Re ...

  3. (转)MySQL 加锁处理分析

    MySQL 加锁处理分析 原文:http://hedengcheng.com/?p=771 1    背景    1 1.1    MVCC:Snapshot Read vs Current Read ...

  4. MySQL 加锁处理分析

    1    背景    1 1.1    MVCC:Snapshot Read vs Current Read    2 1.2    Cluster Index:聚簇索引    3 1.3    2P ...

  5. MySQL 加锁处理分析-转载

    来自何登成的技术博客     1.1    MVCC:Snapshot Read vs Current Read    2 1.2    Cluster Index:聚簇索引    3 1.3     ...

  6. MySQL 加锁处理分析<转>

    1    背景    1 1.1    MVCC:Snapshot Read vs Current Read    2 1.2    Cluster Index:聚簇索引    3 1.3    2P ...

  7. MySQL加锁处理分析(转)

    add by zhj: 非常棒的一篇文章,是我见过的讲加锁最棒最详细的文章了.之前听过网易的<MySQL微专业>,里面的课程讲的也很好,但锁这块讲的跟 这篇文章相比,还是有差距的.网易&l ...

  8. [好文分享]MySQL 加锁处理分析

    原文转自:http://hedengcheng.com/?p=771 背景 MySQL/InnoDB的加锁分析,一直是一个比较困难的话题.我在工作过程中,经常会有同事咨询这方面的问题.同时,微博上也经 ...

  9. 转:mysql加锁处理分析

    MySQL/InnoDB的加锁分析,一直是一个比较困难的话题.我在工作过程中,经常会有同事咨询这方面的问题.同时,微博上也经常会收到MySQL锁相关的私信,让我帮助解决一些死锁的问题.本文,准备就My ...

随机推荐

  1. 多个类定义attr属性重复的问题:Attribute "xxx" has already been defined

    有时候做自定义控件时就会遇到命名冲突,改变有冲突的名字自然是最直接有效的方式,但是感觉很傻.我搜了下别人的解决方案,觉得很值得借鉴.就是把重名的属性,独立出来写一下,然后在定义时直接写属性名字即可. ...

  2. 《Netty权威指南》

    <Netty权威指南> 基本信息 作者: 李林锋 出版社:电子工业出版社 ISBN:9787121233432 上架时间:2014-5-29 出版日期:2014 年6月 开本:16开 页码 ...

  3. Installing Hyperledger Fabric v1.1 on Ubuntu 16.04 — Part II &  Part III

    This entire tutorial is the second part of the installation of Hyperledger Fabric v1.1. In the previ ...

  4. http://download.csdn.net/detail/yanzi1225627/6548337

    [2013.9.8网络首发]导入Android4.2源码里的Gallery2和Camera模块至Eclipse全过程 上次导入的时候是新建的一个user library,然后把所需要的四个库文件放里面 ...

  5. Pytorch之CrossEntropyLoss() 与 NLLLoss() 的区别

    (三)PyTorch学习笔记——softmax和log_softmax的区别.CrossEntropyLoss() 与 NLLLoss() 的区别.log似然代价函数 pytorch loss fun ...

  6. LeetCode 总结

    LeetCode 方法详解

  7. WebView JS交互 addJavascriptInterface MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  8. 亚马逊AWS CentOS7(linux)改为用户名密码登录

    1.进入AWS系统 略 系统为:centos 7 fox.风 2.设置ROOT密码 sudo passwd root 1 3.修改配置文件 sudo vim /etc/ssh/sshd_config ...

  9. 教程 | Kaggle网站流量预测任务第一名解决方案:从模型到代码详解时序预测

    https://mp.weixin.qq.com/s/JwRXBNmXBaQM2GK6BDRqMw 选自GitHub 作者:Artur Suilin 机器之心编译 参与:蒋思源.路雪.黄小天 近日,A ...

  10. php ci框架中载入css和js文件失败的原因及解决方法

    在将html页面整合到ci框架里面的时候,载入css和js失败. 原因是ci框架是入口的框架 对框架中文件的全部请求都须要经过index.php处理完毕,当载入外部的css和js文件的时候要使 用ba ...