排他锁理解,MySQL实践

先上定义:

排他锁又称为写锁,简称X锁,顾名思义,排他锁就是不能与其他锁并存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁,但是获取排他锁的事务是可以对数据就行读取和修改。

在此先引入MySQL中锁的分类:

其中,独占锁是写锁,可理解为传统意义上的读写锁,读读不互斥,读写互斥,写写互斥。

排他锁用法:

SELECT ... FROM UPDATE;

排他锁的申请前提:没有线程对该结果集中的任何行数据使用排他锁或共享锁,否则申请会阻塞。

for update仅适用于InnoDB,且必须在事务块(BEGIN/COMMIT)中才能生效。在进行事务操作时,通过“for update”语句,MySQL会对查询结果集中每行数据都添加排他锁,其他线程对该记录的更新与删除操作都会阻塞。排他锁包含行锁、表锁。

验证排他锁,设计一张表:

/* 开启事务1 */
BEGIN;
/* 查询name为张三的数据并加上排他锁 */
SELECT * FROM test WHERE name = '张三' FOR UPDATE;
/* 延迟10秒执行 */
SELECT SLEEP(10);
/* 尝试修改  name = '张三' 的数据 */
UPDATE test SET balance = 5000 WHERE name = '张三';
/* 延迟15秒执行 */
SELECT SLEEP(15);
/* 提交事务1 */
COMMIT;

开启事务1的执行过程如下:


同时开启事务二:

/* 开启事务2 */
BEGIN;
/* 普通查询name = '张三'的数据 */
SELECT * FROM test WHERE name = '张三';
/* 提交事务2 */
COMMIT;

事务二很快执行完成了,执行结果如下:

可以看出在事务一开启了排他锁以后,其他事务(事务二)仍然可以进行读操作,并产生了不可重复读的结果(在事务一没提交之前,事务一修改张三的余额为5000,事务二读取的张三的余额却为7000,待事务一执行完毕后,事务二读取的张三的余额变为5000)。

如果事务一不变的情况下

/* 开启事务1 */
BEGIN;
/* 查询name为张三的数据并加上排他锁 */
SELECT * FROM test WHERE name = '张三' FOR UPDATE;
/* 延迟10秒执行 */
SELECT SLEEP(10);
/* 尝试修改  name = '张三' 的数据 */
UPDATE test SET balance = 5000 WHERE name = '张三';
/* 延迟15秒执行 */
SELECT SLEEP(15);
/* 提交事务1 */
COMMIT;

事务二对张三的余额进行修改操作

/* 开启事务2 */
BEGIN;
/* 尝试修改  name = '张三' 的数据 */
UPDATE test SET balance = 2000 WHERE name = '张三';
/* 提交事务2 */
COMMIT;

可以看到在事务一开启排他锁的期间,事务二无法进行修改操作,等待20多秒事务一提交后才执行了事务二。事务二在事务一后执行,所以张三的余额被修改为2000。

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值