【MySQL锁篇】一、MySQL当中有哪些锁

本文为博主对于《小林coding》网站的学习笔记,详情请参考原网站

目录

①全局锁 

    全局锁的使用:

   全局锁的应用场景:

    全局锁的缺点

    比较高效的备份方式

②表级锁

       (Ⅰ)表锁

      (Ⅱ)元数据锁(MDL)

       MDL锁的设计初衷:

       MDL锁的工作场景:

       MDL锁,是在什么时候进行释放的

       为什么写锁不释放,后续的读操作都会被阻塞

     (Ⅲ)Auto-INC锁

       innodb_autoinc_lock_mode(用来控制选用AUTO-INC锁还是轻量级锁)

  (IV)意向锁  

 ③行级锁(所有的锁,都是锁住索引)

  (Ⅰ)Record Lock:记录锁:针对某一条记录读取时候加的锁。

(Ⅱ)Gap Lock:只存在于可重复读的隔离界别的间隙锁

(Ⅲ)Next-key Lock:也被称为临建锁


①全局锁 

    全局锁的使用:

    如果想使用全局锁,那么需要用到下面这一条指令:

flush tables with read lock

       执行之后,整个数据库就处于只读状态了,无论是执行对于数据的操作:insert、delete、update还是对于表结构的增删改查,都会被阻塞

       如果想要释放全局锁,就需要使用如下的语句:

unlock tables

   全局锁的应用场景:

    全局锁主要用于做全库逻辑备份。


    全局锁的缺点

       加上全局锁,意味着整个数据库处于只读状态了,如果此时仍然有许多的客户端对于这个数据库进行读取操作,那么会产生很大的业务停滞。

        要知道,在大厂的一些网络产品当中,每一秒都有数以百万甚至千万的访问量。这个时候,哪怕是服务器卡顿了短短的一两秒,都有可能造成非常大的损失的。


    比较高效的备份方式

       在可重复读的隔离级别下面,数据库的存储引擎是支持可重复读的隔离级别的,那么在备份数据库的时候,会先创建Read View,然后再Read View以及mvcc的支持下,数据的备

份期间,其他事物仍然可以对数据进行更新操作。

       关于mvcc和Read View,都已经在这一篇文章当中提及到了。

MySQL事物以及事物的四大特性,隔离级别的简单介绍_mysql中指定事物的特征的语句是_革凡成圣211的博客-CSDN博客https://blog.csdn.net/weixin_56738054/article/details/127857770?spm=1001.2014.3001.5501

       但是,对于MyISAM这一种存储引擎,它不支持事物,因此,在备份数据的时候就一定要受用全局锁来处理了。


②表级锁

       在MySQL当中,里面的表级锁有下面这几种:表锁、元数据锁(MDL)、意向锁、AUTO-INC锁。

      接下来将分别介绍这几种锁


       (Ⅰ)表锁  

        如果想对于某一张表加锁,假如是t_student表加锁。

        可以使用到下面这两行命令(一种是读锁,另外一种是写锁)

        大致就是:lock table +表的名称 +read/write

//表级别的共享锁,也就是读锁;
lock tables t_student read;

//表级别的独占锁,也就是写锁;
lock tables t_stuent write;

       当某一个线程使用了两条指令之后,也就是lock tables t_student read之后,所有的线程

(包括执行第一条sql语句的线程)如果想要对这一个表当中的数据进行修改操作(包括增删

    改)都会阻塞等待。但是,如果单纯的select语句,不会进行阻塞等待。


      (Ⅱ)元数据锁(MDL)

       我们其实不需要显示地使用MDL,因为当我们对于数据库表进行操作的时候,会自动给这个表加上MDL:

        对一张表进行数据变更,也就是CRUD操作的时候,加的是MDL读锁

        对一张表做结构变更的时候,加的是MDL写锁。


       MDL锁的设计初衷:

        为了防止在有线程对表的结构作修改的时候,其他线程对于这个表内容进行增删改查造成的影响。同时,也防止一个线程对于表的内容进行增删改查的时候,其他线程对于表的结构进行修改。

       MDL锁的工作场景:

        当有线程(假设是线程A)执行crud操作的时候,会对这一张表施加一个MDL读锁。

        如果此时其他线程(假设是线程B)想要更改表的结构,那么,它会申请MDL写锁,它将会被阻塞,直到线程A执行完毕,释放锁。

       当有线程对这个表的结构进行修改的时候,会对这个表加一个MDL写锁。此时如果有其他线程执行crud操作,那么它会申请一个MDL读锁,然后申请失败被阻塞,直到表的结构变更完成。

       MDL锁,是在什么时候进行释放的

        MDL锁,是在事物提交之后,才会释放的。这也就意味着,事物执行期间,MDL锁将会一直被占有,直到事物执行结束。

        如果有以下的场景:

        1.线程A启动了一个事物,执行过程当中,使用了一条查询的sql语句(select...),当执行这个语句的时候,就先对这一个表加上了MDL读锁。但是,事物A一直没有提交

        2.线程B也执行相同的查询语句(select...),也会对这个表加一个MDL读锁。此时并不会发生阻塞,因为"读与读"之间不会发生冲突。

        3.接着,线程C执行了修改表的字段的任务,那么它就会加一个MDL写锁。由于MDL锁此时被占用着,因此,线程C无法获取到MDL写锁

        但是由于事物A一直不提交,就存在另外一个问题:此时如果这个表后面有更多的请求过来,那这个时候,对于这张表后续的select语句,都会被阻塞了,这个时候,数据库的线程很快就会饱满了。

       为什么写锁不释放,后续的读操作都会被阻塞

        因为,默认写锁的等级是比读锁高的,因此,如果写锁不释放,其他线程也无法获取到读锁。

        因此,在表创建好之后,并且有大量数据的时候,千万不要随随便便改动数据。


     (Ⅲ)Auto-INC锁

        我们在实际的开发当中,一般都会把表里面的主键字段设置为单调递增的。

        AUTO-INC是一种特殊的表机制,在执行一条新增的sql语句的时候,会加一个表级别

AUTO-INC锁。等插入完毕之后,这个Auto-INC锁会被释放掉。

        这样,当多个事物共同插入的时候,就会产生比较大的阻塞。

        因此,MySQL又提供了一种轻量级的锁来实现自增。

       innodb_autoinc_lock_mode(用来控制选用AUTO-INC锁还是轻量级锁)

        自5.1.2.22版本开始

innodb_autoinc_lock_mode对应的值说明
0采用Auto-INC锁,语句执行结束之后才释放
1(0与2的中间态)

①对于普通insert语句,在申请一个自增过后的值就释放;

②对于insert...selectt这样的语句,需要等语句执行结束之后,整行数据插入完之后再释放

2采用轻量级锁:给被修饰为单调递增的字段赋值一个自增过后的值,就释放锁

  (IV)意向锁  


 ③行级锁(所有的锁,都是锁住索引)

   MySQL支持行级锁,MyIsm不支持行级别的锁。

   首先,需要了解一下共享锁(S锁)独占锁(X锁)

   共享锁:读读共享,读写互斥

   独占锁:写写互斥,读写互斥

 以下是两种不同的select语句 

//对读取的记录加共享锁
select ... lock in share mode;

//对读取的记录加独占锁
select ... for update;

 以下是两种不同的锁之间的的互斥情况:

 

       需要注意的是:在同一个事物当中,即使两个sql语句各自持有不同类型的锁,也不会产生阻塞等待的情况。

       见不兼容的情况,一定是在不同的事物当中的

  例如:

 对于这一行数据:

 carId为2的这一行数据,a为2

但是在同一个事物当中:

执行第二次的时候,可以看到,输出了两个结果:

 说明此时第二个sql语句没有阻塞等待。


(Ⅰ)Record Lock:记录锁:针对某一条记录读取时候加的锁。

      记录锁也是有X锁和S锁的区别之分的。

      可以对某一条记录加上共享锁,也可以对某一条记录加上记录锁。


      当一个事物对一条记录加上S型记录锁之后,其他事物可以继续对这一行记录加S型记录锁

      当一个事物对一条记录加上X型记录锁之后,其他事物不可以继续对这一行记录加上任何X型或者S型的任何记录锁。


      对于一张表,如果执行如下sql语句:

select*form table where id=1 for update

       事物会对表当中主键id为1的数据加上X型记录锁,如果其他事物对于这一条记录进行删除或者修改操作,就会被阻塞。

       如果其他事物执行insert,就会抛出一个异常:主键冲突异常


      但是,当前事物,如果对于这一行记录进行crud操作,是允许的!!!!

select...for update是什么时候释放的: 

select...for update是在事物开启的时候,加锁的。是在事物提交之后释放的。


(Ⅱ)Gap Lock:只存在于可重复读的隔离界别的间隙锁

假如一张表当中,有一个id范围为(3,5)的间隙锁,那么其他事物就无法插入4这一行数据。

此处使用的间隙,是属于当前读的方式来避免幻读的。

间隙锁之间是互相兼容的。即使一个X,另外一个也是X,不会发生锁冲突。 间隙锁是兼容的,它是为了防止幻读现象发生而特意设定的。


(Ⅲ)Next-key Lock:也被称为临建锁

是记录所+间隙锁的组合,锁定一个范围,并且包括记录本身。

在间隙锁当中,可以理解为范围都是开区间的。

在下图当中,临建锁的范围为(3,5],那么也就意味着,如果一个事物持有范围为(3,5]的临建锁,那么其他的事物无法插入id为4的这一条记录,也无法修改id为5的这一条记录。

 对于临建锁来说,X型锁和X型锁是冲突的。

 比如一个事物持有了范围为(3,5]的临建锁,那么就需要考虑需要使用X型还是S型的锁。

 这个时候,相当于加了一个临建锁

select*from table where id>3 and id<=5 for update

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值