前面咱们经过查询语句,更新语句了解了 MySQL 的 innodb 的内部结构以及执行的流程,以后咱们讲了有关索引的内容,经过介绍 innodb 的逻辑存储结构和 B+Tree的模型推演来引出索引的概念,并阐述了咱们如何经过咱们对索引的了解对 MySQL 进行性能优化;再到后面,咱们来到了事务的篇章,咱们分别讲了事务的四大特性以及隔离级别,至于关于隔离级别的实现,咱们总共有两种实现方案,LBCC 以及 MVCC,在上一篇章中,咱们着重讲了 MVCC 的相关介绍,关于锁的方面,咱们且看这一篇章。php
老规矩,先上飞机票:html
前面提到的脑图以下,想要完整高清图片能够到微信个人公众号下【6曦轩】下回复 MySQL 脑图获取: mysql
官网把锁分红了 8 类。因此咱们把前面的两个行级别的锁(Shared and Exclusive Locks),和两个表级别的锁(Intention Locks)称为锁的基本模式。面试
后面三个 Record Locks、Gap Locks、Next-Key Locks,咱们把它们叫作锁的算法,也就是分别在什么状况下锁定什么范围。算法
咱们讲到 InnoDB 里面既有行级别的锁,又有表级别的锁,咱们先来分析一下这两种锁定粒度的一些差别。sql
表锁,顾名思义,是锁住一张表;行锁就是锁住表里面的一行数据。锁定粒度,表锁确定是大于行锁的。数据库
大于。
为何?
表锁只须要直接锁住这张表就好了,而行锁,还须要在表里面去检索这一行数据,因此表锁的加锁效率更高。性能优化
大于,由于当咱们锁住一张表的时候,其余任何一个事务都不能操做这张表。可是咱们锁住了表里面的一行数据的时候,其余的事务还能够来操做表里面的其余没有被锁定的行,因此表锁的冲突几率更大。
表锁的冲突几率更大,因此并发性能更低,这里并发性能就是小于。bash
InnoDB 里面咱们知道它既支持表锁又支持行锁,另外一个经常使用的存储引擎 MyISAM 支持什么粒度的锁?这是第一个问题。第二个就是 InnoDB 已经支持行锁了,那么它也能够经过把表里面的每一行都锁住来实现表锁,为何还要提供表锁呢?
要搞清楚这个问题,咱们就要来了解一下 InnoDB 里面的基本的锁的模式(lock mode),这里面有两个行锁和两个表锁。
第一个行级别的锁就是咱们在官网看到的 Shared Locks (共享锁),咱们获取了一行数据的读锁之后,能够用来读取数据,因此它也叫作读锁,注意不要在加上了读锁之后去写数据,否则的话可能会出现死锁的状况。并且多个事务能够共享一把读锁。那怎么给一行数据加上读锁呢?
咱们能够用 select …… lock in share mode; 的方式手工加上一把读锁。
释放锁有两种方式,只要事务结束,锁就会自动事务,包括提交事务和结束事务。
咱们也来验证一下,看看共享锁是否是能够重复获取。
Transaction 1 | Transaction 2 |
---|---|
begin; | |
SELECT * FROM student WHERE id=1 LOCK IN SHARE MODE; | |
- | begin; |
- | SELECT * FROM student WHERE id=1 LOCK IN SHARE MODE;// OK |
第二个行级别的锁叫作 Exclusive Locks(排它锁),它是用来操做数据的,因此又叫作写锁。只要一个事务获取了一行数据的排它锁,其余的事务就不能再获取这一行数据的共享锁和排它锁。
排它锁的加锁方式有两种,第一种是自动加排他锁。咱们在操做数据的时候,包括增删改,都会默认加上一个排它锁。
还有一种是手工加锁,咱们用一个 FOR UPDATE 给一行数据加上一个排它锁,这个不管是在咱们的代码里面仍是操做数据的工具里面,都比较经常使用。
释放锁的方式跟前面是同样的。
排他锁的验证:
Transaction 1 | Transaction 2 |
---|---|
begin; | |
UPDATE student SET sname = '猫老公 555' WHERE id=1; | |
- | begin; |
- | SELECT * FROM student WHERE id=1 LOCK IN SHARE MODE; // BLOCKED |
- | SELECT * FROM student where id=1 FOR UPDATE; // BLOCKED |
- | DELETE FROM student where id=1 ; // BLOCKED |
这个是两个行锁,接下来就是两个表锁。
意向锁是什么呢?咱们彷佛历来没有听过,也历来没有使用过,其实他们是由数据库本身维护的。
也就是说,当咱们给一行数据加上共享锁以前,数据库会自动在这张表上面加一个意向共享锁。
当咱们给一行数据加上排他锁以前,数据库会自动在这张表上面加一个意向排他锁。
反过来讲:
若是一张表上面至少有一个意向共享锁,说明有其余的事务给其中的某些数据行加上了共享锁。
若是一张表上面至少有一个意向排他锁,说明有其余的事务给其中的某些数据行加上了排他锁。
select * from t2 where id =4 for update;
复制代码
TABLE LOCK table example
.t2
trx id 24467 lock mode IX RECORD LOCKS space id 64 page no 3 n bits 72 index PRIMARY of table example
.t2
trx id 24467 lock_mode X locks rec but not gap
那么这两个表级别的锁存在的意义是什么呢?第一个,咱们有了表级别的锁,在InnoDB 里面就能够支持更多粒度的锁。它的第二个做用,咱们想一下,若是说没有意向锁的话,当咱们准备给一张表加上表锁的时候,咱们首先要作什么?是否是必须先要去判断有没其余的事务锁定了其中了某些行?若是有的话,确定不能加上表锁。那么这个时候咱们就要去扫描整张表才能肯定能不能成功加上一个表锁,若是数据量特别大,好比有上千万的数据的时候,加表锁的效率是否是很低?
可是咱们引入了意向锁以后就不同了。我只要判断这张表上面有没有意向锁,若是有,就直接返回失败。若是没有,就能够加锁成功。因此 InnoDB 里面的表锁,咱们能够把它理解成一个标志。就像火车上厕全部没有人使用的灯,是用来提升加锁的效率的。
Transaction 1 | Transaction 2 |
---|---|
begin; | |
SELECT * FROM student where id=1 FOR UPDATE; | |
- | BEGIN; |
- | LOCK TABLES student WRITE; // BLOCKED UNLOCK TABLES; // 释放表锁的方式 |
以上就是 MySQL 里面的 4 种基本的锁的模式,或者叫作锁的类型。
有问题?能够给我留言或私聊 有收获?那就顺手点个赞呗~
固然,也能够到个人公众号下「6曦轩」,
回复“学习”,便可领取一份 【Java工程师进阶架构师的视频教程】~
回复“面试”,能够得到: 【本人呕心沥血整理的 Java 面试题】
回复“MySQL脑图”,能够得到 【MySQL 知识点梳理高清脑图】
因为我咧,科班出身的程序员,php,Android以及硬件方面都作过,不过最后仍是选择专一于作 Java,因此有啥问题能够到公众号提问讨论(技术情感倾诉均可以哈哈哈),看到的话会尽快回复,但愿能够跟你们共同窗习进步,关于服务端架构,Java 核心知识解析,职业生涯,面试总结等文章会不按期坚持推送输出,欢迎你们关注~~~