MySql之深入分析MySql 的锁

时光毁灭记忆、已成空白 提交于 2020-01-31 11:21:47


数据准备

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for emp
-- ----------------------------
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

SET FOREIGN_KEY_CHECKS = 1;
insert into emp 
values (1,"gaoxinfu11");
insert into emp 
values(2,"gaoxinfu22");
insert into emp 
values(3,"gaoxinfu33");
insert into emp 
values(4,"gaoxinfu44");

1.InnoDB 存储引擎的锁

1.1.锁的类型 -八中类型

https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html
在这里插入图片描述

1.2.锁的基本模式

1.2.1.表锁

1.表锁,顾名思义,是锁住一张表;

1.2.2.行锁

1.行锁就是锁住表里面的一行数据。

1.2.3.关于行锁和表锁的粒度概述

1.锁的粒度主要是指加锁的数据范围;
2.表锁肯定是大于行锁的。
3.加锁效率,表锁也是大于行锁的;表锁只需要直接锁住这张表就行了,而行锁,还需要在表里面去检索这一行数据,所以表锁的加锁 效率更高。
4.表锁的冲突概率肯定是大于行锁的,
  因为当我们锁住一张表的时候,其他任何一个事务都不能操作这张表。但是我们锁住了表里面的一行数据的时候,
  其他的事务还可以来操作表里面的其他没有被锁定的行,所以表锁的冲突概率更大。
  表锁的冲突概率更大,所以并发性能更低

1.3.锁的类型

1.3.1.Shared Locks (共享锁) ----->行级别的锁

在这里插入图片描述

1.3.1.1.概念

1.共享锁又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改;

1.3.1.2.如何设置共享锁

select * from emp where id=1 LOCK IN SHARE MODE;

在share-mode-tx01这个事务中进行加锁

BEGIN;
select * from emp where id=1 LOCK IN SHARE MODE;

在这里插入图片描述

1.3.1.2.如何释放共享锁

commit或者rollback

1.3.1.3.案例1-查询加锁后查询

在share-mode-tx02事务中进行查询

BEGIN;
select * from emp where id=1 ;

在这里插入图片描述

结论

1.共享锁很明显,加锁之后,我们还是能够进行查询操作的;

1.3.1.3.案例2-查询加锁后更新

同样的share-mode-tx01事务中我们进行加锁之后,操作下面的事务
在share-mode-tx03事务中我们对同一条记录进行更新

BEGIN;
update emp set name='gaoxinfu-sm' where id=1;

在这里插入图片描述

1.同一条记录被加共享锁之后,因为被锁住,无法进行更新/删除等操作;

1.3.2.Exclusive Locks(排它锁)又称写锁或者X锁 ----->行级别的锁

在这里插入图片描述

1.3.2.1.概念

1.排他锁不能与其他锁并存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的锁(共享锁、排他锁),
  只有该获取了排他锁的事务是可以对数据行进行读取和修改。  

1.3.2.2.如何设置排它锁

自动加锁 delete/update/insert
delete/update/insert 默认加上X锁; 
手动加锁 FOR UPDATE
手动:select * from emp where id=1 FOR UPDATE;

1.3.2.3.如何释放排它锁 commit/rollback;

commit/rollback;

1.3.2.3.案例演示

在事务exclusive-mode-01中进行更新id=1的记录

begin;
update emp set name='gaoxinfu-x-mode' where id=1;

在这里插入图片描述

在事务exclusive-mode-02中进行再次更新id=1的记录

begin;
update emp set name='gaoxinfu-x-mode-02' where id=1;

在这里插入图片描述

1.很明显由于在事务exclusive-mode-01之中没有提交(没有结束)也就是排它锁加锁之中,所以在事务exclusive-mode-02之中再次
  去更新的时候,不会成功;

1.3.3.意向锁

在这里插入图片描述

1.3.3.1.概念

1.首先意向锁是一个表锁,是对整个表的一个加锁操作;
2.意向锁包含两种:意向共享锁(Intention Shared Lock,简称IS锁)和意向排它锁(Intention Exclusive Lock)
3.意向锁是什么呢?我们好像从来没有听过,也从来没有使用过,其实他们是由数据 库自己维护的。
  也就是说,
  当我们给一行数据加上共享锁之前,数据库会自动在这张表上面加一个意向共享锁。
  当我们给一行数据加上排他锁之前,数据库会自动在这张表上面加一个意向排他锁。
  反过来讲:
  如果一张表上面至少有一个意向共享锁,说明有其他的事务给其中的某些数据行加上了共享锁。 
  如果一张表上面至少有一个意向排他锁,说明有其他的事务给其中的某些数据行加上了排他锁。

1.3.3.1.如何设置意向锁

LOCK TABLES table_name WRITE/READ; # 

1.3.3.2.意向锁的意义

第一个,我们有了表级别的锁,在 InnoDB 里面就可以支持更多粒度的锁。
第二个,我们想一下,如果说没有意向锁的话,当我们准备给一张表加上表锁的时候,我们首先要做什么?是不是必须先要去
       判断有没其他的事务锁定了其中了某些行?如果有的话,肯定不能加上表锁。那么这个时候我们就要去扫描整张表才
       能确定能不能成功加上一个表锁,如果数据量特别大,比如有上千万的数据的时候,加表锁的效率是不是很低?       
但是我们引入了意向锁之后就不一样了。我只要判断这张表上面有没有意向锁,
   如果有,就直接返回失败。
   如果没有,就可以加锁成功。
所以InnoDB里面的表锁,我们可以把它理解成一个标志。就像火车上厕所有没有人使用的灯,是用来提高加锁的效率的。

1.3.3.3.意向锁使用场景

1.3.3.4.案例演示- 行锁之后进行表锁试验

在事务intention-mode-01这个事务中我们先手动加锁(排它锁)

BEGIN;
select * from emp where id=1 for update;

在这里插入图片描述

在intention-mode-02事务中对表进行加意向锁

BEGIN;
LOCK TABLES emp WRITE;

在这里插入图片描述

1.如上一旦如果表里记录有如果有被锁定的,那么我们去加表锁的话,是无法成功的;

1.3.3.5.案例演示- 表锁之后进行行锁试验

我们先在intention-mode-02这个事务之中先进行表的加锁

BEGIN;
LOCK TABLES emp WRITE;

在这里插入图片描述

然后在intention-mode-01这个事务中进行对记录id=1加锁

BEGIN;
select * from emp where id=1 for update;

在这里插入图片描述

1.如上表一旦被锁定,是无法进行行锁的

1.3.3.6.解锁

UNLOCK TABLES;

1.4.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!