MySQL与InnoDB下共享锁与排他锁实例分析

65次阅读
没有评论

共计 3025 个字符,预计需要花费 8 分钟才能阅读完成。

这篇文章主要介绍“MySQL 与 InnoDB 下共享锁与排他锁实例分析”的相关知识,丸趣 TV 小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“MySQL 与 InnoDB 下共享锁与排他锁实例分析”文章能帮助大家解决问题。

共享锁 (Shared Lock)

共享锁、S 锁、读锁  ,都是他的叫法。

而我,喜欢叫他 共享读锁。

A shared (S) lock permits the transaction that holds the lock to read。 

共享锁允许持有该锁的事务读取。

这里的共享是,读读共享。

也就是说,无论是 行级或是表级,如果 对某数据 上了 共享读锁,其他事务可以继续 读(也就是允许持有共享读锁),但是 不能写,也就是 读写互斥。

顺便介绍一下如何   加 共享锁(共享读锁):

上表级共享锁,也就是表级共享读锁:

select * from table(表) lock in share mode ;

上行级共享锁,也就是行级共享读锁:

select * from table(表)where id = 10 
lock in share mode
 ;

在这啰唆一点,注意了,在 InnoDB 下,不是你想用行锁就用行锁的,行锁的触发条件我们再次回顾下(开篇有提到):

排他锁 (Exclusive Lock)

排他锁、写锁、X 锁  ,都是他的叫法。

而我,喜欢叫他 独占写锁。

An exclusive (X) lock permits the transaction that holds the lock to update or delete。

独占(X)锁允许持有锁的事务更新或删除。

独占,这个词。打过篮球没,以前初中打篮球不懂事,拿着球就不传。同学就说我,你好独啊。

是的,我很独。就跟这个独占写锁(排他锁)一样,很独。

当事务对某数据加上了 独占写锁(排他锁),只有当前事务能够对这数据执行修改或删除操作。

其他事务,不能读,不能写。因为 这个锁 很独,必须等这个很独 的锁 使用完了(释放),其他事务才有机可乘。

所以,独占写锁(排他锁)是,读写互斥、写写互斥的。

顺便介绍一下如何   加 排他锁(独占写锁):

上表级排他锁,也就是表级独占写锁:

select * from table
 for update ;

上行级排他锁,也就是行级独占写锁:

select * from table where id =10 
 for update
 ;

在这我再再啰唆一点,注意了,在 InnoDB 下,不是你想用行锁就用行锁的,行锁的触发条件我们再次回顾下(开篇有提到):

上面的 sql 能上行级排他锁,是因为命中了索引,id 是 索引。

也许看到这里,你对 共享锁   排他锁还只是云里雾里,大致知道个什么读读共享、读写互斥、写写互斥啥的。

所以,我们需要再次 从上帝视角再看一次 这两个锁,

红色   事务操作一

蓝色     事务操作二

共享锁(共享读锁)排他锁(独占写锁)共享锁(共享读锁)可以,兼容,一起读不可以,不兼容,想写得等共享锁没了排他锁(独占写锁)不可以,不兼容,上了排他锁,别人啥都不能动不可以,不兼容,上了排他锁,别人啥都不能动

那么如果你看到这里,还是对 共享锁   排他锁还只是云里雾里。

那我只有动手了!

实战介绍,演示 所谓的读读共享、读写互斥、写写互斥。

在演示读读共享、读写互斥、写写互斥前,我必须点明一点!

在这篇文章里面,我介绍了一些上 共享锁(共享读锁)、排他锁(独占写锁)的方式。但是 可以看到写的查询 sql 都是后面加了东西的, lock in share mode,for update  …. 等。

所以我想点明的一点是,

  如果是使用 普通的查询,是 什么锁都没上的!

就好像平时我们经常写的

select * from table;
select * from table where age=18;

select 语句默认不会加任何锁类型 select 语句默认不会加任何锁类型 select 语句默认不会加任何锁类型

而排他锁,除了 select …. for update ,InnoDB 引擎 默认的修改、插入、删除(update,insert,delete)都是会给操作的相关数据 加 排他锁的 .

废话不多说,我们上才艺:

准备一些用于测试的数据。

建表:

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
 `age` int(11) NULL DEFAULT NULL,
 `sex` tinyint(1) NULL DEFAULT NULL,
 PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;

搞点模拟数据:

(id 主键索引)

第一个小实践:

我们不废话,我们直接上共享读锁,看看是不是能 符合刚才我们的理论 读读共享,读写互斥!

1. 我们先给 id= 3 这数据上个 共享读锁:

2. 基于当前状况,我们再执行一下查询语句,也是使用共享读锁的:

3. 那么也是基于当前情况,我们再执行一下使用排他写锁的查询语句,可以发现 读写互斥了:

4. 验证下,我们查看当前是否存在事务在等待锁:

可以从结果中看出 事务请求 id 34847 在等待锁:

我们再查询一下,那些事务在使用锁,
可以从结果看出,34844 事务在使用 S 锁,也就是共享读锁;

而 34847 事务 在使用 X 锁,也就是排他写锁(但是由于共享读锁先上了,所以读写互斥了),所以造成了 34847 事务 在等待锁。

5. 那么如果我们一直不 COMMIT 共享读锁,34847 事务 会永无止息地等待锁吗?  那么肯定是不可能允许这种一直等待的场景的:

所以 mysql 会有个等待锁资源超时的机制,这种情况就会直接返回查询失败的结果。

根据第一个小实践,我们得出一个很明显的结论:

当某数据上了 共享读锁 S 时,只允许其他事务上共享读锁 S,因为读读共享;

不允许其他事务上 独占写锁 X(除非把这个共享读锁 S 释放掉),因为读写互斥。

第二个小实践:

1. 我们直接给某行数据上个排他写锁 X (注意我们的事务是没有执行 COMMIT 的):

MySQL 与 InnoDB 下共享锁与排他锁实例分析

2. 我们接下来去 通过共享读锁去获取数据,看看会发生什么?

MySQL 与 InnoDB 下共享锁与排他锁实例分析

这就是 独占写锁 X 的 读写互斥、写写互斥(写写互斥的场景就不展示了).

再验证下,我们看下是不是存在事务在等待锁资源:
MySQL 与 InnoDB 下共享锁与排他锁实例分析

3. 那么如果独占写锁一直不释放,其余事务时一直等待吗?

也是一样,会等待超时返回查询失败:
MySQL 与 InnoDB 下共享锁与排他锁实例分析

补充一个小实践:

1. 还是一样,先给某个数据上 独占写锁,不 COMMIT:

MySQL 与 InnoDB 下共享锁与排他锁实例分析

2. 执行普通的查询,select:
MySQL 与 InnoDB 下共享锁与排他锁实例分析

可以看到,普通的 select 语句能正常获取,为什么?因为前面我们提到了:

MySQL 与 InnoDB 下共享锁与排他锁实例分析

所以我必须再啰唆一下,所谓的 读读共享,读写互斥,写写互斥,都是对于锁资源来说的,如果你都没有锁资源竞争,那肯定不存在什么互斥什么互斥了。

关于“MySQL 与 InnoDB 下共享锁与排他锁实例分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注丸趣 TV 行业资讯频道,丸趣 TV 小编每天都会为大家更新不同的知识点。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-15发表,共计3025字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)