你需要理解的关于MySQL的锁知识

一、前言

MySQL 的锁按照范围可以分为全局锁、表锁、行锁,其中行锁是由数据库引擎实现的,并不是所有的引擎都提供行锁,MyISAM 就不支持行锁,所以文章介绍行锁会以InnoDB引擎为例来介绍行锁。

二、全局锁

MySQL 提供全局锁来对整个数据库实例加锁。

语法:

FLUSH TABLES WITH READ LOCK

这条语句一般都是用来备份的,当执行这条语句后,数据库所有打开的表都会被关闭,并且使用全局读锁锁定数据库的所有表,同时,其他线程的更新语句(增删改),数据定义语句(建表,修改表结构)和更新类的事务提交都会被阻塞。

在mysql 8.0 以后,对于备份,mysql可以直接使用备份锁。

语句:

LOCK INSTANCE FOR BACKUPUNLOCK INSTANCE

这个锁的作用范围更广,这个锁会阻止文件的创建,重命名,删除,包括 REPAIR TABLE TRUNCATE TABLE, OPTIMIZE TABLE操作以及账户的管理都会被阻塞。当然这些操作对于内存临时表来说是可以执行的,为什么内存表不受这些限制呢?因为内存表不需要备份,所以也就没必要满足这些条件。

三、表锁

Mysql的表级别锁分为两类,一类是元数据锁(Metadata Lock,MDL),一种是表锁。

元数据锁(MDL) 不需要显式使用,在访问一个表的时候会被自动加上。这个特性需要MySQL5.5版本以上才会支持,当对一个表做增删改查的时候,该表会被加MDL读锁;当对表做结构变更的时候,加MDL写锁。MDL锁有一些规则:

读锁之间不互斥,所以可以多线程多同一张表进行增删改查。读写锁、写锁之间是互斥的,为了保证表结构变更的安全性,所以如果要多线程对同一个表加字段等表结构操作,就会变成串行化,需要进行锁等待。MDL的写锁优先级比MDL读锁的优先级,但是可以设置max_write_lock_count系统变量来改变这种情况,当写锁请求超过这个变量设置的数后,MDL读锁的优先级会比MDL写锁的优先级高。(默认情况下,这个数字会很大,所以不用担心写锁的优先级下降)MDL的锁释放必须要等到事务结束才会释放。

所以我们在操作数据库表结构时候必须要注意不要使用长事务,这里具体是什么意思呢?我举个例子说明下:

上图表示演示了4个session执行语句,首先SessionA开启了事务没有提交,接着sessionB执行查询,因为是获取MDL读锁,所以互相不影响,可以正常执行,SessionC新增一个字段,由于MDL写和读是互斥的,所以SessionC会被阻塞,之后SessionD开始执行一个查询语句,由于SessionC的阻塞,所以SessionD也阻塞了。所以,我们模拟的SessionA的事务是长事务,然后后面执行了修改表结构,会导致后续对该表所有的读写操作都不可行了。所以在实际场景中,如果业务请求比较频繁的时候,对表结构进行修改的时候就有可能导致该库的线程被阻塞满。

表锁 的语法如下:

LOCK TABLES tbl_name [[AS] alias] lock_type [, tbl_name [[AS] alias] lock_type] ...lock_type: { READ [LOCAL] | [LOW_PRIORITY] WRITE}UNLOCK TABLES

表锁分为读锁和写锁,读锁不互斥,但是获取读锁不能写入数据,其他没有获取到读锁的session也是可以读取表的,所以读锁的目的就是限制表被写。如果表被读锁锁住后,再执行插入语句会报错,报错如下:

1099 - Table 'XXXX' was locked with a READ lock and can't be updated

写锁被获取后可以对表进行读写,写锁是互斥的,一旦某个session获取到表的写锁,另外的session无法访问这个表,直到写锁被释放。

表的解锁可以使用unlock tables解锁,也可以客户端口自动解锁。lock tables锁表会独占式的锁住表,除了限制其他线程对该表的读写,也会限制本线程接下来的操作对象。

四、行锁(InnoDB)

MySQL的行锁是在引擎层面实现的,所以这里讨论的也是InnoDB引擎下的行锁,下面会详细介绍InnoDB下常见的几种行锁

4.1 共享锁

共享锁能允许事务获取到锁后进行读操作,共享锁是不互斥的,一个事务获取到共享锁后,另外一个事务也可以获取共享锁,获取共享锁后不能进行写操作。

4.2 排它锁

排他锁允许事务获取到锁后进行更新一行或者删除某一行操作,排他锁顾名思义是互斥的,一个事务获取到排他锁后,其他事务不能获取到排他锁,直到这个锁被释放。

4.3 意向锁

InnoDB支持多种粒度的锁,允许行锁和表锁共存,这里说的意向锁其实是一种表级别的锁,但是我把它放在行锁里面是因为它不会单独存在,它的出现肯定会伴随着行锁(共享锁或者排他锁),它主要的目的就是表示将要锁定表中的行或者正在锁定表中的行。

意向锁根据和行锁的组合可以分为:

  • 意向排他锁:表明将要在表中的某些行获取排他锁
  • 意向共享锁:表明将要在表中的某些行获取共享锁

意向锁的获取必须在行锁获取之前,也就是说获取共享锁之前必须先要获取共享意向锁,对于排他锁也是一样的道理。

那么这个意向锁到底有什么作用呢?

解释这个之前,我们先看看意向锁和行锁之前的兼容关系:

--- 排他锁(X) 意向排他锁(IX) 共享锁(S) 意向共享锁(IS)
排他锁(X) 冲突 冲突 冲突 冲突
意向排他锁(IX) 冲突 兼容 冲突 兼容
共享锁(S) 冲突 冲突 兼容 兼容
意向共享锁(IS) 冲突 兼容 兼容 兼容

我们假设有2个事务A和事务B,事务获取到了共享锁,锁住了表中的某一行,这一行只能读,不能写,现在事务B要申请整个表的写锁。如果事务B申请成功,那么肯定是可以对表中所有的行进行写操作的,那么肯定与A获取的行锁冲突。数据库为了避免这种冲突,就会进行冲突检测,那么如何去检测呢?有两种方式:

判断表是否已经被其他事务用表级锁锁住。判断表中的每一行是否被行锁锁住。

判断表中的每一行需要遍历所有记录,效率太差,所以数据库就用第一种方式去做冲突检测,也就是用到了意向锁。

总结

本文主要从MySQL的加锁范围来分析了MySQL的锁,MySQL根据加锁范围可以分为全局锁、表锁、行锁。全局锁和表锁是MySQL自己实现,行锁都是由引擎层面去实现。InnoDB下的行锁主要分为共享锁和排他锁。共享锁请求后,行只能读,共享锁之间不互斥。排他锁获取后能更新和删除行,排他锁与其他锁都互斥。最后我在行锁的基础上提到了意向锁,意向锁主要表示正在锁住行或者即将锁住行,为了在锁冲突检测中提高效率。当然InnoDB下还有其他锁,比如间隙锁,记录锁,Next-Key锁等,这些都不在本文的探讨范围之内,如有兴趣的同学可以自行研究。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • MySQL InnoDB中的锁机制深入讲解

    写在前面 数据库本质上是一种共享资源,因此在最大程度提供并发访问性能的同时,仍需要确保每个用户能以一致的方式读取和修改数据.锁机制(Locking)就是解决这类问题的最好武器. 首先新建表 test,其中 id 为主键,name 为辅助索引,address 为唯一索引. CREATE TABLE `test` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` int(11) NOT NULL, `address` int(11) NOT NULL, P

  • 一次神奇的MySQL死锁排查记录

    背景 说起Mysql死锁,之前写过一次有关Mysql加锁的基本介绍,对于一些基本的Mysql锁或者死锁都有一个简单的认识,可以看下这篇文章为什么开发人员需要了解数据库锁.有了上面的经验之后,本以为对于死锁都能手到擒来,没想到再一个阳光明媚的下午报出了一个死锁,但是这一次却没想象的那么简单. 问题初现 在某天下午,突然系统报警,抛出个异常: 仔细一看好像是事务回滚异常,写着的是因为死锁回滚,原来是个死锁问题,由于我对Mysql锁还是有一定了解的,于是开始主动排查这个问题. 首先在数据库中查找Inn

  • Mysql查询正在执行的事务以及等待锁的操作方式

    使用navicat测试学习: 首先使用set autocommit = 0;(取消自动提交,则当执行语句commit或者rollback执行提交事务或者回滚) 在打开一个执行update 查询 正在执行的事务: SELECT * FROM information_schema.INNODB_TRX 根据这个事务的线程ID(trx_mysql_thread_id): 从上图看出对应的mysql 线程:一个94362 (第二个正在等待锁)另一个是93847(第一个update 正在执行 没有提交事务

  • 一个mysql死锁场景实例分析

    前言 最近遇到一个mysql在RR级别下的死锁问题,感觉有点意思,研究了一下,做个记录. 涉及知识点:共享锁.排他锁.意向锁.间隙锁.插入意向锁.锁等待队列 场景 隔离级别:Repeatable-Read 表结构如下 create table t ( id int not null primary key AUTO_INCREMENT, a int not null default 0, b varchar(10) not null default '', c varchar(10) not n

  • 实例讲解MySQL中乐观锁和悲观锁

    数据库管理系统中并发控制的任务是确保在多个事务同时存取数据库中同一数据不破坏事务的隔离性和统一性以及数据库的统一性 乐观锁和悲观锁式并发控制主要采用的技术手段 悲观锁 在关系数据库管理系统中,悲观并发控制(悲观锁,PCC)是一种并发控制的方法.它可以阻止一个事务以影响其他用户的方式来修改数据.如果一个事务执行的操作的每行数据应用了锁,那只有当这个事务锁释放,其他事务才能够执行与该锁冲突的操作 悲观并发控制主要应用于数据争用激烈的环境,以及发生并发冲突时使用锁保护数据的成本要低于回滚事务的成本环境

  • 你需要理解的关于MySQL的锁知识

    一.前言 MySQL 的锁按照范围可以分为全局锁.表锁.行锁,其中行锁是由数据库引擎实现的,并不是所有的引擎都提供行锁,MyISAM 就不支持行锁,所以文章介绍行锁会以InnoDB引擎为例来介绍行锁. 二.全局锁 MySQL 提供全局锁来对整个数据库实例加锁. 语法: FLUSH TABLES WITH READ LOCK 这条语句一般都是用来备份的,当执行这条语句后,数据库所有打开的表都会被关闭,并且使用全局读锁锁定数据库的所有表,同时,其他线程的更新语句(增删改),数据定义语句(建表,修改表

  • mysql 悲观锁与乐观锁的理解及应用分析

    本文实例讲述了mysql 悲观锁与乐观锁.分享给大家供大家参考,具体如下: 悲观锁与乐观锁是人们定义出来的概念,你可以理解为一种思想,是处理并发资源的常用手段. 不要把他们与mysql中提供的锁机制(表锁,行锁,排他锁,共享锁)混为一谈. 一.悲观锁 顾名思义,就是对于数据的处理持悲观态度,总认为会发生并发冲突,获取和修改数据时,别人会修改数据.所以在整个数据处理过程中,需要将数据锁定. 悲观锁的实现,通常依靠数据库提供的锁机制实现,比如mysql的排他锁,select .... for upd

  • 深入理解mysql各种锁

    目录 锁的概述 锁分类 对数据库操作的粒度分 对数据操作的类型分 mysql锁 不同存储引擎支持锁级别 锁介绍 MyISAM表锁 如何添加表锁 加解锁 锁竞争 锁的使用情况 InnoDB锁 行锁 锁升级 间隙锁 锁争用 总结 优化建议 锁的概述 锁是计算机协调多个进程或线程并访问某一资源的机制 在数据库中,除传统的计算机资源(如cpu.RAM.I/O等)的争用以外,数据也是一种供许多用户共享的资源,如果保证数据并发访问的一致性,有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性

  • 一文搞懂MySQL元数据锁(MDL)

    目录 一.什么是metadata lock 二.MDL和行锁有什么区别 三.MDL为什么会造成系统崩溃 四.MDL的生命周期有多长 五.如何快速找到阻塞源头 六.本文开始的案例最终如何解决 小结 某日,路上收到用户咨询,为了清除空间,想删除某200多G大表数据,且已经确认此表不再有业务访问,于是执行了一条命令‘delete from bigtable’,但好长时间也没删完,经过咨询后,获知drop table删除表速度快,而且能彻底释放空间,于是又在另外一个session中执行了‘drop ta

  • MySQL使用表锁和行锁的场景详解

    目录 前言 全局锁 表级锁 表锁 元数据锁 意向锁 行级锁 总结 前言 MySQL Innodb 的锁可以说是执行引擎的并发基础了,有了锁才能保证数据的一致性.众所周知,我们都知道 Innodb 有全局锁.表级锁.行级锁三种,但你知道什么时候会用表锁,什么时候会用行锁吗? 虽然对 MySQL 的知识点挺熟悉的,但一开始看到这个问题,树哥也是有点懵,我还真没从这个角度去思考过.大家可以暂时 1 分钟思考下答案,后面我将带大家弄清楚这个问题. 对于这个问题,我只能粗略地想起一些片段,例如: 对于表级

  • MySQL 行锁和表锁的含义及区别详解

    一.前言 对于行锁和表锁的含义区别,在面试中应该是高频出现的,我们应该对MySQL中的锁有一个系统的认识,更详细的需要自行查阅资料,本篇为概括性的总结回答. MySQL常用引擎有MyISAM和InnoDB,而InnoDB是mysql默认的引擎.MyISAM不支持行锁,而InnoDB支持行锁和表锁. 相对其他数据库而言,MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制. MySQL大致可归纳为以下3种锁: 表级锁:开销小,加锁快:不会出现死锁:锁定粒度大,发生锁冲突的概率

  • MySQL InnoDB 锁的相关总结

    1.  Shared and Exclusive Locks shared lock (译:共享锁) exclusive lock (译:排它锁.独占锁) InnoDB实现了标准的行级锁,其中有两种类型的锁,共享锁(shared locks)和排他锁(exclusive locks). A shared (S) lock permits the transaction that holds the lock to read a row. An exclusive (X) lock permits

  • 深入理解r2dbc在mysql中的使用

    简介 mysql应该是我们在日常工作中使用到的一个非常普遍的数据库,虽然mysql现在是oracle公司的,但是它是开源的,市场占有率还是非常高的. 今天我们将会介绍r2dbc在mysql中的使用. r2dbc-mysql的maven依赖 要想使用r2dbc-mysql,我们需要添加如下的maven依赖: <dependency> <groupId>dev.miku</groupId> <artifactId>r2dbc-mysql</artifact

  • mysql中锁机制的最全面讲解

    目录 前言 全局锁 全库逻辑备份 FTWRL和set global readonly=true的区别 表级锁 MDL锁 行锁 死锁 记录锁 间隙锁 临键锁 乐观锁和悲观锁 总结 前言 根据加锁的粒度区分 全局锁 表级锁 行锁 记录锁 间隙锁 临键锁 根据加锁的场景 乐观锁 悲观锁 全局锁 锁对象是:整个数据库实例 Flush tables with read lock (FTWRL)-会让整个库处于只读状态 使用场景: 做全库逻辑备份 全库逻辑备份 为什么要进行全局锁才能进行数据备份呢? 就比如

  • MySQL悲观锁与乐观锁的实现方案

    目录 前言 实战 1.无锁 2.悲观锁 3.乐观锁 总结 前言 悲观锁和乐观锁是用来解决并发问题的两种思想,在不同的平台有着各自的实现.例如在Java中,synchronized就可以认为是悲观锁的实现(不严谨,有锁升级的过程,升级到重量级锁才算),Atomic***原子类可以认为是乐观锁的实现. 悲观锁 具有强烈的独占和排他特性,在整个处理过程中将数据处于锁定状态,一般是通过系统的互斥量来实现.当其他线程想要获取锁时会被阻塞,直到持有锁的线程释放锁. 乐观锁 对数据的修改和访问持乐观态度,假设

随机推荐