Mysql中S 锁和 X 锁的区别

MySQL锁机制详解
本文介绍了MySQL中的S锁和X锁,详细解释了这两种锁的工作原理及其应用场景,并进一步探讨了快照读与当前读的区别。

S 锁,英文为 Shared Lock,中文译作共享锁,有时候我们也称之为读锁,即 Read Lock。S 锁之间是共享的,或者说是互不阻塞的。

1. S 锁

S 锁,英文为 Shared Lock,中文译作共享锁,有时候我们也称之为读锁,即 Read Lock。S 锁之间是共享的,或者说是互不阻塞的。

当事务读取一条记录时,需要先获取该记录的 S 锁。

举个例子:

事务 T1 对记录 R1 加上了 S 锁,那么事务 T1 可以读取 R1 这一行记录,但是不能修改 R1,其他事务 T2 可以继续对 R1 添加 S 锁,但是不能添加 X 锁,只有当 R1 上面的 S 锁释放了,才能加上 X 锁。

举一个加 S 锁的例子,如下图:
在这里插入图片描述
此时,对于 id=1 的这条记录,只能读取不能修改了。假设在另外一个事务 T 中,执行如下 SQL 是没问题的,因为 S 锁是共享锁,S 锁和 S 锁之间是兼容的:

select * from user where id=1 lock in share mode;

但是如果执行如下 SQL 则会被阻塞,因为修改数据需要获取 X 锁,而 S 锁和 X 锁不兼容:

update user set username='javaboy' where id=1;

上面这个更新语句内部会获取 X 锁,对于一些手动添加了 X 锁的查询语句,也会阻塞,例如下面这个:

在这里插入图片描述

可以看到,这个 SQL 执行之后就被阻塞了。

2. X 锁

X 锁,英文为 Exclusive Lock,中文译作排他锁,有时候我们也称之为写锁,即 Write Lock。如同它的名字,X 锁是具有排他性的,即一个写锁会阻塞其他的 X 锁和 S 锁。

当事务需要修改一条记录时,需要先获取该记录的 X 锁。

举个例子:

事务 T1 对记录 R1 加上了 X 锁,那么事务 T1 即可以读取 R1 也可以修改 R1,而其他事务则不能对 R1 再添加任何锁,直到 T1 释放了 R1 上的锁。

如上文图示,锁定读的格式是这样的:

select .... for update;

3. 当前读与快照读

由上面这两种锁,又引申出来两种读:

3.1 快照读

快照读(SnapShot Read)是一种一致性不加锁的读,是 InnoDB 存储引擎并发如此之高的核心原因之一。

在可重复读的隔离级别下,事务启动的时候,就会针对当前库拍一个照片(快照),快照读读取到的数据要么就是拍照时的数据,即事务开启那一瞬间数据库中的数据,要么就是当前事务自身插入/修改过的数据。

我们日常所用的不加锁的查询,都属于快照读,这个我就不演示了。

3.2 当前读

与快照读相对应的就是当前读,当前读就是读取最新数据,而不是历史版本的数据,换言之,在可重复读隔离级别下,如果使用了当前读,也可以读到别的事务已提交的数据。

松哥举个例子:

MySQL 事务开启两个会话 A 和 B。

首先在 A 会话中开启事务并查询 id 为 1 的记录:
在这里插入图片描述

接下来我们在 B 会话中对 id 为 1 的数据进行修改,如下:

在这里插入图片描述

注意 B 会话不要开启事务或者开启了及时提交事务,否则 update 语句占用一把排他锁会导致一会在 A 会话中用锁时发生阻塞。

接下来,回到 A 会话中继续做查询操作,如下:
在这里插入图片描述

可以看到,A 会话中第一个查询是快照读,读取到的是当前事务开启时的数据状态,后面两个查询则是当前读,读取到了当前最新的数据(B 会话中修改后的数据)。

### 3.1 共享(S)与排他(X)的核心区别 共享(Shared Lock,S排他(Exclusive Lock,X)是数据库并发控制中两种最基本的机制,它们在事务并发执行时用于控制对数据的访问权限,确保数据的一致性完整性。 共享允许多个事务同时读取同一数据资源,但禁止任何事务对该资源进行修改。这种适用于只读操作,例如查询商品库存、用户余额等场景。在MySQL中,可以通过在查询语句后添加 `LOCK IN SHARE MODE` 来显式地对数据加上共享[^4]。 排他则与共享相反,它不允许任何其他事务对同一资源进行读取或写入操作。只有持有排他的事务可以对资源进行读写。排他通常用于数据修改操作,如插入(INSERT)、更新(UPDATE)、删除(DELETE)等。在MySQL中,可以通过在查询语句后添加 `FOR UPDATE` 来显式地对数据加上排他[^2]。 ### 3.2 并发控制与冲突矩阵 共享排他之间的兼容性决定了事务能否并发执行。数据库系统通过兼容性矩阵来控制不同之间的互斥关系: - 多个事务可以同时对同一数据加共享(S),即共享之间是兼容的。 - 如果一个事务对数据加了共享(S),其他事务不能加排他(X),即S阻止X。 - 如果一个事务对数据加了排他(X),其他事务既不能加S也不能加X,即X阻止所有其他。 这种机制确保了在并发环境中,数据的修改不会导致脏读、不可重复读或幻读等问题[^1]。 ### 3.3 应用场景对比 共享(S)适用于高并发读操作的场景,例如在电商系统中查看商品库存时,多个用户可以同时读取库存数量,但不能在此期间修改库存,以避免超卖或数据不一致问题。 排他(X)适用于需要修改数据的场景,例如在银行系统中执行转账操作时,必须对账户余额加排他,防止其他事务同时修改该余额,从而保证事务的原子性一致性。 ### 示例代码 以下是在MySQL中使用共享排他的SQL示例: ```sql -- 使用共享(S) SELECT * FROM accounts WHERE user_id = 1001 LOCK IN SHARE MODE; -- 使用排他(X) SELECT * FROM accounts WHERE user_id = 1001 FOR UPDATE; ``` 在上述SQL语句中,`LOCK IN SHARE MODE`表示对查询结果加共享,`FOR UPDATE`表示对查询结果加排他。这些会在事务提交或回滚后释放[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值