深入理解SELECT ... LOCK IN SHARE MODE和SELECT ... FOR UPDATE
概念和区别
SELECT ... LOCK IN SHARE MODE走的是IS锁(意向共享锁),即在符合条件的rows上都加了共享锁,这样的话,其他session可以读取这些记录,也可以继续添加IS锁,但是无法修改这些记录直到你这个加锁的session执行完成(否则直接锁等待超时)。
SELECT ... FOR UPDATE 走的是IX锁(意向排它锁),即在符合条件的rows上都加了排它锁,其他session也就无法在这些记录上添加任何的S锁或X锁。如果不存在一致性非锁定读的话,那么其他session是无法读取和修改这些记录的,但是innodb有非锁定读(快照读并不需要加锁),for update之后并不会阻塞其他session的快照读取操作,除了select ...lock in share mode和select ... for update这种显示加锁的查询操作。
通过对比,发现for update的加锁方式无非是比lock in share mode的方式多阻塞了select...lock in share mode的查询方式,并不会阻塞快照读。
应用场景
在我看来,SELECT ... LOCK IN SHARE MODE的应用场景适合于两张表存在关系时的写操作,拿mysql官方文档的例子来说,一个表是child表,一个是parent表,假设child表的某一列child_id映射到parent表的c_child_id列,那么从业务角度讲,此时我直接insert一条child_id=100记录到child表是存在风险的,因为刚insert的时候可能在parent表里删除了这条c_child_id=100的记录,那么业务数据就存在不一致的风险。正确的方法是再插入时执行select * from parent where c_child_id=100 lock in share mode,锁定了parent表的这条记录,然后执行insert into child(child_id) values (100)就ok了。
但是如果是同一张表的应用场景,举个例子,电商系统中计算一种商品的剩余数量,在产生订单之前需要确认商品数量>=1,产生订单之后应该将商品数量减1。
1 select amount from product where product_name='XX';
2 update product set amount=amount-1 where product_name='XX';
显然1的做法是是有问题,因为如果1查询出amount为1,但是这时正好其他session也买了该商品并产生了订单,那么amount就变成了0,那么这时第二步再执行就有问题。
那么采用lock in share mode可行吗,也是不合理的,因为两个session同时锁定该行记录时,这时两个session再update时必然会产生死锁导致事务回滚。以下是操作范例(按时间顺序)
session1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from test_jjj lock in share mode;
+-----+------------+
| id | name |
+-----+------------+
| 234 | asdasdy123 |
| 123 | jjj |
+-----+------------+
2 rows in set (0.00 sec)
session2(同样锁定了相同的行)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from test_jjj lock in share mode;
+-----+------------+
| id | name |
+-----+------------+
| 234 | asdasdy123 |
| 123 | jjj |
+-----+------------+
2 rows in set (0.00 sec)
session1(这时session1再update时就会引起锁等待)
mysql> update test_jjj set name='jjj1' where name='jjj';
session2(这时session2同样update就会检测到死锁,回滚session2,注意执行时间不要超过session1的锁等待超时检测时间,即不要超过innodb_lock_wait_timeout设置的值)
mysql> update test_jjj set name='jjj1' where name='jjj';
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
session1(此时session1执行完成)
mysql> update test_jjj set name='jjj1' where name='jjj';
Query OK, 1 row affected (29.20 sec)
Rows matched: 1 Changed: 1 Warnings: 0
通过该案例可知lock in share mode的方式在这个场景中不适用,我们需要使用for update的方式直接加X锁,从而短暂地阻塞session2的select...for update操作;以下是操作范例
session1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from test_jjj for update;
+-----+------------+
| id | name |
+-----+------------+
| 234 | asdasdy123 |
| 123 | jjj1 |
+-----+------------+
2 rows in set (0.00 sec)
session2(此时session2处于锁等待状态,得不到结果)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from test_jjj for update;
session1(这时session1 update之后提交,可完成)
mysql> update test_jjj set name='jjj1' where name='jjj';
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0 Changed: 0 Warnings: 0
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
session2(session1提交之后session2刚才的查询结果就出来了,也就可以再次update往下执行了)
mysql> select * from test_jjj for update;
+-----+------------+
| id | name |
+-----+------------+
| 234 | asdasdy123 |
| 123 | jjj1 |
+-----+------------+
2 rows in set (37.19 sec)
mysql> select * from test_jjj for update;
+-----+------------+
| id | name |
+-----+------------+
| 234 | asdasdy123 |
| 123 | jjj1 |
+-----+------------+
2 rows in set (37.19 sec)
mysql> update test_jjj set name='jjj1' where name='jjj';
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0 Changed: 0 Warnings: 0
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
通过对比,lock in share mode适用于两张表存在业务关系时的一致性要求,for update适用于操作同一张表时的一致性要求。
深入理解SELECT ... LOCK IN SHARE MODE和SELECT ... FOR UPDATE的更多相关文章
- SELECT ... LOCK IN SHARE MODE和SELECT ... FOR UPDATE locks在RR模式下可以看到最新的记录
14.5.2.4 Locking Reads 锁定读: 如果你查询数据然后插入或者修改相关数据在相同的事务里, 常规的SELECT 语句不能给予足够的保护. 其他事务可以修改或者删除你刚查询相同的记录 ...
- [MySQL] 行级锁SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE
一.译文 翻译来自官方文档:Locking Reads If you query data and then insert or update related data within the same ...
- lock in share mode 和 select for update
lock in share mode 和 select for update 2018年07月11日 01:57:58 道不虚行只在人 阅读数 146 版权声明:欢迎转载,请注明出处 https ...
- 转 MYSQL SELECT ... FOR UPDATE and SELECT ... LOCK IN SHARE MODE Locking Reads
原文: http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html In some circumstances, a consis ...
- 浅谈select for update 和select lock in share mode的区别
有些情况下为了保证数据逻辑的一致性,需要对SELECT的操作加锁.InnoDB存储引擎对于SELECT语句支持两种一致性的锁定读(locking read)操作. . SELECT …… FOR UP ...
- SELECT LOCK IN SHARE MODE and FOR UPDATE
Baronwrote nice article comparing locking hints in MySQL and SQL Server. In MySQL/Innodb LOCK IN SHA ...
- Select for update/lock in share mode 对事务并发性影响
select for update/lock in share mode 对事务并发性影响 事务并发性理解 事务并发性,粗略的理解就是单位时间内能够执行的事务数量,常见的单位是 TPS( transa ...
- Mysql加锁过程详解(4)-select for update/lock in share mode 对事务并发性影响
Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...
- (转载)Select for update/lock in share mode 对事务并发性影响
select for update/lock in share mode 对事务并发性影响 事务并发性理解 事务并发性,粗略的理解就是单位时间内能够执行的事务数量,常见的单位是 TPS( transa ...
随机推荐
- 【BZOJ4421】[Cerc2015] Digit Division 动态规划
[BZOJ4421][Cerc2015] Digit Division Description 给出一个数字串,现将其分成一个或多个子串,要求分出来的每个子串能Mod M等于0. 将方案数(mod 1 ...
- 【BZOJ3673/3674】可持久化并查集/可持久化并查集加强版 可持久化线段树
[BZOJ3674]可持久化并查集加强版 Description Description:自从zkysb出了可持久化并查集后……hzwer:乱写能AC,暴力踩标程KuribohG:我不路径压缩就过了! ...
- c#学习笔记之使用 TableLayoutPanel 控件设置窗体布局
使用 TableLayoutPanel 控件设置窗体布局 在 Visual Studio IDE 左侧,找到“工具箱”选项卡. 选择“工具箱”选项卡,随即将显示工具箱.(或者,在菜单栏上,依次选择“视 ...
- <2014 05 21> 互联网时代的C语言——Go(2)
**************************************************************************************************** ...
- 服务器端Session和客户端Session(和Cookie区别)
Session其实分为客户端Session和服务器端Session. 当用户首次与Web服务器建立连接的时候,服务器会给用户分发一个 SessionID作为标识.SessionID是一个由24个字符组 ...
- pandas 修改指定列中所有内容
如下图: 读取出来的 DataFrame “code” 列内容格式为:“浪潮信息(000977.XSHE)” 格式,目标效果是:000977.XSHE 代码: df["code"] ...
- Keras网络层之“关于Keras的层(Layer)”
关于Keras的“层”(Layer) 所有的Keras层对象都有如下方法: layer.get_weights():返回层的权重(numpy array) layer.set_weights(weig ...
- Ubuntu Linux下通过代理(proxy)使用git上github.com
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/loveaborn/article/details/24575659 github.com.作为程序猿 ...
- 《Redis官方文档》用Redis构建分布式锁
用Redis构建分布式锁 在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章描述如何用Redis实现一个分布式锁管理器,但是这些库实现的方式差别很大,而且很多简 ...
- Linux用户、群组及权限
由于对文件的操作需要切换到相应文件夹下进行,所以对文件内容的修改,最基本的是需要其文件夹执行的权限. 文件夹的读权限(read)可以独立行使,但是对文件夹内容的写权限(对其内文件的新建.删除.重命名) ...