百分百源码网-让建站变得如此简单! 登录 注册 签到领金币!

主页 | 如何升级VIP | TAG标签

当前位置: 主页>网站教程>数据库> 我所了解的MySQL五:锁及加锁法则
分享文章到:

我所了解的MySQL五:锁及加锁法则

发布时间:12/01 来源:未知 浏览: 关键词:
mysql教程栏目介绍MySQL的第五篇文章,对于锁及加锁法则。

mysql教程栏目介绍MySQL的第五篇文章,对于锁及加锁法则。

MySQL 系列的第五篇,主要内容是锁(Lock),包含锁的粒度分类、行锁、间隙锁以及加锁法则等。

MySQL 引入锁的目的是为理解决并发写的题目,比方两个事务同时对统一笔记录进行写操纵,要是允许它们同时进行,那就会发生脏写的题目,这是任何一种隔离级别都不允许产生的异样状况,而锁的作用就是让两个并发写操纵按照一定的次序施行,以免脏写题目。

第一申明本文中所运用到的示例

CREATE TABLE `user`  (  `id` int(12) NOT NULL AUTO_INCREMENT,  `name` varchar(36) NULL DEFAULT NULL,  `age` int(12) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,  INDEX `age`(`age`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1;insert into user values (5,'重塑',5),(10,'达达',10),(15,'刺猬',15); 

本文所述示例都是在 MySQL InnoDB 存储引擎以及可反复读(Repeatable Read)隔离级别下。

1. 锁的粒度分类

从锁的粒度来看,MySQL 中的锁可以分为全局锁、表级锁和行锁三种。

1.1 全局锁

全局锁会将整个数据库都加上锁,此时数据库将处于只读状态,任何修改数据库的语句,包含 DDL(Data Definition Language)及增删改的 DML(Data Manipulation Language)语句都将被阻塞,直到数据库全局锁开释。

最常运用到全就锁的地方就是进行全库备份,我们可以通过下列的语句实现全局锁的加锁与开释锁操纵:

-- 加全局锁flush tables with read lock;-- 开释全局锁unlock table; 

若客户端链接断开,也会主动开释全局锁。

1.2 表级锁

表级锁会将整张表加上锁,MySQL 中的表级锁有:表锁元数据锁(Meta Data Lock)、意向锁(Intention Lock)和自增锁(AUTO-INC Lock)。

1.2.1 表锁

表锁的加锁和开释锁方式:

  • 加锁:lock table tableName read/write;
  • 开释锁:unlock table;

需要注意的是,表锁的加锁也限定了统一个客户端链接的操纵权限,如加了表级读锁(lock table user read),那么在统一个客户端链接中在开释表级读锁之前,对统一张表(user 表)也只能进行读操纵,没法进行写操纵,而其他客户端链接对该表(user 表)只能进行读操纵,没法进行写操纵。

如加了表级写锁(lock table user write),在统一个客户端链接中可对表进行读写操纵,而其他客户端链接既没法进行读操纵也没法进行写操纵。

1.2.2 元数据锁

第二种表级锁是元数据锁(MDL, Meta Data Lock),元数据锁会在客户端拜访表的时候主动加锁,在客户端提交事务时开释锁,它防止了下列场景涌现的题目:

sessionAsessionB
begin;
select * from user;

alter table user add column birthday datetime;
select * from user;

如上表,sessionA 开启了一个事务,并进行一次查询,在这之后别的一个客户端 sessionBuser 表新增了一个 birthday 字段,然后 sessionA 再进行一次查询,要是没有元数据锁,就可能会涌现在统一个事务中,先后两次查询到的记载,表字段列数纷歧致的状况,这显然是需要以免的。

DDL 操纵对表加的是元数据写锁,对其他事务的元数据读写锁都不兼容;DML 操纵对表加的是元数据读锁,可与其他事务的元数据读锁同享,但与其他事务的元数据写锁不兼容。

1.2.3 意向锁

第三种表级锁是意向锁,它表示事务想要猎取一张表中某几行的锁(同享锁或排它锁)。

意向锁是为了不在表中已经存在行锁的状况下,另一个事务去申请表锁而扫描表中的每一行可否存在行锁的系统耗损。

sessionAsessionB
begin;
select * from user where id=5 for update;

flush table user read;

例如,sessionA 开启了一个事务,并对 id=5 这一行加上了行级排它锁,此时 sessionB 将对 user 表加上表级排它锁(只有 user 表中有一行被其他事务持有读锁或写锁即加锁失败)。

要是没成心向锁,sessionB 将扫描 user 表中的每一行,推断它们可否被其他事务加锁,然后才干得出 sessionB 的此次表级排它锁加锁可否成功。

而有了意向锁之后,在 sessionB 将对 user 表加锁时,会直接推断 user 表可否被其他事务加上了意向锁,如有则加锁失败,若无则可以加上表级排它锁。

意向锁的加锁法则

  • 事务在猎取行级同享锁(S锁)前,必需猎取表的意向同享锁(IS锁)或意向排它锁(IX锁)
  • 事务在猎取行级排它锁(X锁)前,必需猎取表的意向排它锁(IX锁)

1.2.4 自增锁

第四种表级锁是自增锁,这是一种特别的表级锁,只存在于被设定为 AUTO_INCREMENT 自增列,如 user 表中的 id 列。

自增锁会在 insert 语句施行完成后立刻开释。同时,自增锁与其他事务的意向锁可同享,与其他事务的自增锁、同享锁和排它锁都是不兼容的。

1.3 行锁

行锁是由存储引擎实现的,从行锁的兼容性来看,InnoDB 实现了两种规范行锁:同享锁(Shared Locks,简称S锁)和排它锁(Exclusive Locks,简称X锁)。

这两种行锁的兼容关系与上面元数据锁的兼容关系是同样的,可以用下面的表格表示。

事务A\事务B同享锁(S锁)排它锁(X锁)
同享锁(S锁)兼容冲突
排它锁(X锁)冲突冲突

而从行锁的粒度继续细分,又可以分为记载锁(Record Lock)、间隙锁(Gap Lock)、Next-key Lock

1.3.1 记载锁(Record Lock)

我们个别所说的行锁都是指记载锁,它会把数据库中的指定记载行加上锁。

假如事务A中施行下列语句(未提交):

begin;update user set name='达闻西' where id=5; 

InnoDB 至少会在 id=5 这一行上加一把行级排它锁(X锁),不允许其他事务操纵 id=5 这一行。

需要注意的是,这把锁是加在 id 列的主键索引上的,也就是说行级锁是加在索引上的。

假如此刻有另一个事务B想要施行一条更新语句:

update user set name='大波纹' where id=5; 

这时候,这条更新语句将被阻塞,直到事务A提交今后,事务B才干继续施行。

2. 加锁法则

不晓得大家有没有注意到,我在行锁局部描述记载锁、间隙锁加锁的具体记载时,用的是「至少」二字,并没有细致注明具体加锁的是哪些记载,这是由于记载锁、间隙锁和 Next-key Lock 的加锁法则是十分复杂的,这也是本文主要计议的内容。

对于加锁法则的论述将分为三个方面:独一索引列、普通索引列和普通列,每一方面又将细分为等值查询和范畴查询两方面。

需要注意的是,这里加的锁都是指排它锁。

在开端以前,先来回忆一下示例表以及表中可能存在的行级锁。

mysql> select * from user;
+----+--------+------+| id | name   | age  |
+----+--------+------+|  5 | 重塑   |    5 |
| 10 | 达达   |   10 |
| 15 | 刺猬   |   15 |
+----+--------+------+3 rows in set (0.00 sec) 

表中可能包括的行级锁第一是每一行的记载锁——(5,重塑,5),(10,达达,5),(15,刺猬,15)。

假如 user 表的索引值有最大值 maxIndex 和最小值 minIndex,user 表还可能存在间隙锁(minIndex,5),(5,10),(10,15),(15,maxIndex)。

共三个记载锁和四个间隙锁。

2.1 独一索引列等值查询

第一来说独一索引列的等值查询,这里的等值查询可以分为两种状况:命中与未命中。

当独一索引列的等值查询命中时:

sessionAsessionB
begin;
select * from user where id=5 for update;

insert into user values(1,'斯斯与帆',1),(6,'夏季阳光',6),(11,'告五人',11),(16,'脸孔',16);

update user set age=18 where id=5;(Blocked

update user set age=18 where id=10;

update user set age=18 where id=15;

上表中 sessionB 的施行效果是除了 id=5 行的更新语句被阻塞,其他语句都正常施行。

sessionB 中的 insert 语句是为了检查间隙锁,update 语句是为了检查记载锁(行锁)。施行效果表白 user 表的所有间隙都没有被上锁,记载锁中只要 id=5 这一行被上锁了。

这个边界值与独一索引列范畴查询的道理是同样的,可以参照上文所述来了解,这里未几加赘述了。

《MySQL实战45讲》的作者丁奇以为这是一个 BUG,但并未被官方接收,要是要深究这个边界值的道理,可能就需要看 MySQL 的源码了。

3. 数往知来

  1. MySQL 中的锁按粒度来分可以分为几种?离别描述一下。
  2. MySQL 中行锁的加锁法则?
  3. 请说出下面几条 SQL 的加锁区域:
select * from user where age=10 for update;select * from user where age>=10 and age<11 for update;select id from user where age>=10 and age<11 for update; 

更多相干免费学习举荐:mysql教程(视频)

以上就是我所了解的MySQL五:锁及加锁法则的细致内容,更多请关注 百分百源码网 其它相干文章!

打赏

打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

百分百源码网 建议打赏1~10元,土豪随意,感谢您的阅读!

共有151人阅读,期待你的评论!发表评论
昵称: 网址: 验证码: 点击我更换图片
最新评论

本文标签

广告赞助

能出一分力是一分吧!

订阅获得更多模板

本文标签

广告赞助

订阅获得更多模板