lock in share mode 就是共享锁
如果事务对某行数据加上共享锁之后,可进行读写操作;其他事务可以对该数据加共享锁,但不能加排他锁,且只能读数据,不能修改数据。 某个事务想进行修改数据操作,那他必须等其他事务的共享锁都释放完毕才能进行修改操作。
for update 排他锁,就是行锁
如果事务对数据加上排他锁之后,则其他事务不能对该数据加任何的锁。获取排他锁的事务既能读取数据,也能修改数据。
注:普通 select 语句默认不加锁,而CUD操作默认加排他锁。
例子:
下面例子的前提都是针对同一行数据。
1.同一行数据为前提,两个事务都进行共享锁查询
2.同一行数据为前提,一个事务进行共享锁查询,另一个事务进行修改
第一个占有着共享锁,第二个事务没法更新,必须等第一个事务释放才能进行更新
3.同一行数据为前提,一个进行共享锁查询,另一个先进行共享锁查询,然后update
同第二种,修改的事务就一直在转圈圈,等待事务1提交。事务1不提交,那事务2只能等到超时返回错误。
4.同一行数据为前提,当事务一获得共享锁,另一个事务是否可以获得排它锁
答案是不能,事务二就一直转圈圈,等待1的释放
结论:同一行数据为前提,当一个事务获得共享锁,另一个事务可以获得共享锁进行读操作,但不能进行修改操作,想要修改必须等其他的共享锁释放完毕。还有一个事务获得了共享锁,另一个事务不能获得排它锁
5.同一行数据为前提,一个事务获取到排他锁,另一个事务进行查询
结果是可以的,一个获取排它锁,另一个进行普通查询
6.同一行数据为前提,一个事务获取到排他锁,另一个事务进行共享锁的获取
结果如图2,爱的魔力转圈圈,就一直卡在那里
7.同一行数据为前提,一个事务获取排它锁,另一个事务是否可以进行修改
结果如图2,爱的魔力转圈圈,就一直卡在那里
8.同一行数据为前提,一个事务获取排它锁,另一个是否可以获取排它锁
结果如图2,爱的魔力转圈圈,就一直卡在那里
结论:当前事务获取某行数据排他锁后,其他事务是否可以对该行数据进行读写操作和获取共享锁:其他事务可以读,不可以获取共享锁,不可以写
这里再给读者科普一点,行锁和索引的关系:查询字段未加索引(主键索引、普通索引等)时,使用表锁
注:InnoDB行级锁基于索引实现。
未加索引时,两种行锁情况为(使用表锁):
- 事务1获取某行数据共享锁,其他事务可以获取不同行数据的共享锁,不可以获取不同行数据的排他锁
- 事务1获取某行数据排他锁,其他事务不可以获取不同行数据的共享锁、排他锁
加索引后,两种行锁为(使用行锁):
- 事务1获取某行数据共享锁,其他事务可以获取不同行数据的共享锁、排他锁
- 事务1获取某行数据排他锁,其他事务可以获取不同行数据的共享锁、排他锁
表结果:
CREATE TABLE pf_banner (
id bigint(22) NOT NULL AUTO_INCREMENT,
num int(11) DEFAULT NULL,
title varchar(80) DEFAULT NULL,
url varchar(255) DEFAULT NULL,
img varchar(255) DEFAULT NULL,
status tinyint(4) DEFAULT '1' COMMENT '状态 1:显示 -1不显示',
create_time datetime DEFAULT NULL,
modify_time datetime DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='banner位图片'
例子
1.未加索引,事务1获取某行数据共享锁,事务2更新不同行数据阻塞:
2.未加索引,事务1获取某行数据共享锁,事务2获取不同行数据共享锁成功:
3.未加索引,事务1获取某行数据排他锁,事务2获取不同行数据共享锁阻塞:
4.未加索引,事务1获取某行数据排他锁,事务2获取不同行数据排他锁阻塞:
加索引后表结构:
CREATE TABLE pf_banner (
id bigint(22) NOT NULL AUTO_INCREMENT,
num int(11) DEFAULT NULL,
title varchar(80) DEFAULT NULL,
url varchar(255) DEFAULT NULL,
img varchar(255) DEFAULT NULL,
status tinyint(4) DEFAULT '1' COMMENT '状态 1:显示 -1不显示',
create_time datetime DEFAULT NULL,
modify_time datetime DEFAULT NULL,
PRIMARY KEY (id),
KEY idx_num (num) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='banner位图片'
1.加索引后,事务1获取某行数据共享锁,事务2可以更新不同行数据:
2.加索引后,事务1获取某行数据共享锁,事务2获取不同行数据共享锁成功:
3.加索引后,事务1获取某行数据排他锁,事务2获取不同行数据排他锁成功:
4.加索引后,事务1获取某行数据排他锁,事务2获取不同行数据共享锁成功:
科普小知识2:索引数据重复率太高会导致全表扫描:当表中索引字段数据重复率太高,则MySQL可能会忽略索引,进行全表扫描,此时使用表锁。可使用 force index 强制使用索引。
操作步骤
1.事务1,执行鼠标选中的内容
2.事务2,执行鼠标选中的内容
你会发现事务2会一直转圈圈,其实在执行update的时候,已经是表锁了。导致事务2 进行行锁的时候,需要等待事务1的释放
现在,我们使用强制锁进行更新操作。
当你使用强制索引的时候,就会发现更新成功了。
当然数据重复降低,也是能成功的
注意:下图中第5行代码应该是不带 “force_index(idx_num)”
原文链接:https://blog.csdn.net/xiao__miao/article/details/106052984(本文对原文中一些细节描述做了修改)