Mysql中的共享锁和排他锁

一、前言

  刚开始学习MySQL中锁的时候,网上一查出来一堆,什么表锁、行锁、读锁、写锁、悲观锁、乐观锁等等等,直接整个人就懵了。好多文章都尽量把很多锁给列举一遍,生怕写少了内容不够丰富,有的连死锁、分布式锁都给写上了。其实给这些锁归归类,就清楚很多了!本篇文章只聊共享锁排他锁,不过我们也不妨先看下锁分类。

二、锁分类

1. 按粒度

按照锁粒度划分,可以将锁划分成行锁页锁表锁

这里只解释下行锁:按照行的粒度对数据进行锁定,锁定粒度小,发生锁冲突概率低,可以实现并发都高。但是对于锁的开销比较大,加上会比较慢;在程序中控制不好,可能出现死锁的情况。

说到粒度,顺带说下InnoDB 存储引擎的逻辑结构:所有数据都被逻辑地存放在一个空间内,称为表空间,而表空间由段(sengment)、区(extent)、页(page)组成。Mysql中的共享锁和排他锁_第1张图片

2. 按机制

共享锁(S):又称为读锁,多个事务可以一起读,但都不能写(这里有个细节,如果只有当前事务加了共享锁,那么该事务可以写。),共享锁之间不互斥,共享锁会阻塞排它锁
排他锁(X):又称为写锁,允许获得排他锁的事务更新数据,但是阻止其他事务获得相同数据集的共享锁和排他锁。

3. 按场景

这个跟MySQL没有直接性的关系,只是人们使用锁碰到的问题、或者使用程序解决具体场景的一些锁概念:悲观锁乐观锁分布式锁死锁

三、使用方式

  • 共享锁
-- 对表加共享锁
LOCK TABLE product_comment READ;
-- 对表释放共享锁
UNLOCK TABLE;

-- 对数据集加共享锁
SELECT * FROM table_name WHERE ... lock in share mode;
  • 排他锁
-- 对表加排他锁
LOCK TABLE product_comment WRITE;
-- 对表释放排他锁
UNLOCK TABLE;

-- 对数据集加排他锁
SELECT * FROM table_name WHERE ... for update;

1.对于UPDATE、DELETE、INSERT语句,自动给相关数据加上排他锁。
2.如果数据集过滤条件中不走索引的话,会给全表加锁。

四、实验

1. 共享锁不能写

A事务

begin;
SELECT * FROM user WHERE id = 1 lock in share mode;
update user set name = 'jsk' where id =1;
commit;

B事务

begin;
SELECT * FROM user WHERE id = 1 lock in share mode;
commit;

如果仅执行事务A中的语句,是可以顺利完成的。这里可以证明:只有当前事务加了共享锁,那么该事务可以写
如果仅执行事务A中的前两行,然后执行事务B中前两行,再回头继续执行事务A中的第三行。此时,会一直卡在这里!Mysql中的共享锁和排他锁_第2张图片
这里可以证明:数据行上有共享锁存在,就不能加上排他锁,即不能有写操作。(上面提到过,写操作会自动加上排他锁)

你可能感兴趣的