mysql中的锁机制深入讲解

前言

为了保证数据的一致完整性,任何一个数据库都存在锁定机制。锁定机制的优劣直接应想到一个数据库系统的并发处理能力和性能,所以锁定机制的实现也就成为了各种数据库的核心技术之一。

大概几个月之前项目中用到事务,需要保证数据的强一致性,期间也用到了mysql的锁,但当时对mysql的锁机制只是管中窥豹,所以本文打算总结一下mysql的锁机制。

本文主要论述关于mysql锁机制,mysql版本为5.7,引擎为innodb,由于实际中关于innodb锁相关的知识及加锁方式很多,所以没有那么多精力罗列所有场景下的加锁过程并加以分析,仅根据现在了解的知识,结合官方文档,说说自己的理解,如果发现有不对的地方,欢迎指正。

概述

总的来说,InnoDB共有七种类型的锁:

  • 共享/排它锁(Shared and Exclusive Locks)
  • 意向锁(Intention Locks)
  • 记录锁(Record Locks)
  • 间隙锁(Gap Locks)
  • 临键锁(Next-key Locks)
  • 插入意向锁(Insert Intention Locks)
  • 自增锁(Auto-inc Locks)

mysql锁详解

1. 共享/排它锁(Shared and Exclusive Locks)

  • 共享锁(Share Locks,记为S锁),读取数据时加S锁
  • 排他锁(eXclusive Locks,记为X锁),修改数据时加X锁

使用的语义为:

  • 共享锁之间不互斥,简记为:读读可以并行
  • 排他锁与任何锁互斥,简记为:写读,写写不可以并行

可以看到,一旦写数据的任务没有完成,数据是不能被其他任务读取的,这对并发度有较大的影响。对应到数据库,可以理解为,写事务没有提交,读相关数据的select也会被阻塞,这里的select是指加了锁的,普通的select仍然可以读到数据(快照读)。

2. 意向锁(Intention Locks)

InnoDB为了支持多粒度锁机制(multiple granularity locking),即允许行级锁与表级锁共存,而引入了意向锁(intention locks)。意向锁是指,未来的某个时刻,事务可能要加共享/排它锁了,先提前声明一个意向。

1、意向锁是一个表级别的锁(table-level locking);

2、意向锁又分为:

  • 意向共享锁(intention shared lock, IS),它预示着,事务有意向对表中的某些行加共享S锁;
  • 意向排它锁(intention exclusive lock, IX),它预示着,事务有意向对表中的某些行加排它X锁;

加锁的语法为:

select ... lock in share mode;  要设置IS锁;
select ... for update;       要设置IX锁;

事务要获得某些行的S/X锁,必须先获得表对应的IS/IX锁,意向锁仅仅表明意向,意向锁之间相互兼容,兼容互斥表如下:

  IS IX
IS 兼 容 兼 容
IX 兼 容 兼 容

虽然意向锁之间互相兼容,但是它与共享锁/排它锁互斥,其兼容互斥表如下:

  S X
IS 兼 容 互 斥
IX 互 斥 互 斥

排它锁是很强的锁,不与其他类型的锁兼容。这其实很好理解,修改和删除某一行的时候,必须获得强锁,禁止这一行上的其他并发,以保障数据的一致性。

3. 记录锁(Record Locks)

记录锁,它封锁索引记录,例如(其中id为pk):

create table lock_example(id smallint(10),name varchar(20),primary key id)engine=innodb;

数据库隔离级别为RR,表中有如下数据:

10, zhangsan
20, lisi
30, wangwu

select * from t where id=1 for update;

其实这里是先获取该表的意向排他锁(IX),再获取这行记录的排他锁(我的理解是因为这里直接命中索引了),以阻止其他事务插入,更新,删除id=1的这一行。

4. 间隙锁(Gap Locks)

间隙锁,它封锁索引记录中的间隔,或者第一条索引记录之前的范围,又或者最后一条索引记录之后的范围。依然是上面的例子,InnoDB,RR:

select * from lock_example
where id between 8 and 15
for update;

这个SQL语句会封锁区间(8,15),以阻止其他事务插入id位于该区间的记录。

间隙锁的主要目的,就是为了防止其他事务在间隔中插入数据,以导致“不可重复读”。如果把事务的隔离级别降级为读提交(Read Committed, RC),间隙锁则会自动失效。

5. 临键锁(Next-key Locks)

临键锁,是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间。

默认情况下,innodb使用next-key locks来锁定记录。但当查询的索引含有唯一属性的时候,Next-Key Lock 会进行优化,将其降级为Record Lock,即仅锁住索引本身,不是范围。

举个例子,依然是如上的表lock_example,但是id降级为普通索引(key),也就是说即使这里声明了要加锁(for update),而且命中的是索引,但是因为索引在这里没有UK约束,所以innodb会使用next-key locks,数据库隔离级别RR:

事务A执行如下语句,未提交:

select * from lock_example where id = 20 for update;

事务B开始,执行如下语句,会阻塞:

insert into lock_example values('zhang',15);

如上的例子,事务A执行查询语句之后,默认给id=20这条记录加上了next-key lock,所以事务B插入10(包括)到30(不包括)之间的记录都会阻塞。临键锁的主要目的,也是为了避免幻读(Phantom Read)。如果把事务的隔离级别降级为RC,临键锁则也会失效。

6. 插入意向锁(Insert Intention Locks)

对已有数据行的修改与删除,必须加强互斥锁(X锁),那么对于数据的插入,是否还需要加这么强的锁,来实施互斥呢?插入意向锁,孕育而生。

插入意向锁,是间隙锁(Gap Locks)的一种(所以,也是实施在索引上的),它是专门针对insert操作的。多个事务,在同一个索引,同一个范围区间插入记录时,如果插入的位置不冲突,不会阻塞彼此。

Insert Intention Lock signals the intent to insert in such a way that multiple transactions inserting into the same index gap need not wait for each other if they are not inserting at the same position within the gap.

举个例子(表依然是如上的例子lock_example,数据依然是如上),事务A先执行,在10与20两条记录中插入了一行,还未提交:

insert into t values(11, xxx);

事务B后执行,也在10与20两条记录中插入了一行:

insert into t values(12, ooo);

因为是插入操作,虽然是插入同一个区间,但是插入的记录并不冲突,所以使用的是插入意向锁,此处A事务并不会阻塞B事务。

7. 自增锁(Auto-inc Locks)

自增锁是一种特殊的表级别锁(table-level lock),专门针对事务插入AUTO_INCREMENT类型的列。最简单的情况,如果一个事务正在往表中插入记录,所有其他事务的插入必须等待,以便第一个事务插入的行,是连续的主键值。

AUTO-INC lock is a special table-level lock taken by transactions inserting into tables with AUTO_INCREMENT columns. In the simplest case, if one transaction is inserting values into the table, any other transactions must wait to do their own inserts into that table, so that rows inserted by the first transaction receive consecutive primary key values.

举个例子(表依然是如上的例子lock_example),但是id为AUTO_INCREMENT,数据库表中数据为:

1, zhangsan
2, lisi
3, wangwu

事务A先执行,还未提交: insert into t(name) values(xxx);

事务B后执行: insert into t(name) values(ooo);

此时事务B插入操作会阻塞,直到事务A提交。

总结

以上总结的7种锁,个人理解可以按两种方式来区分:

1. 按锁的互斥程度来划分,可以分为共享、排他锁;

  • 共享锁(S锁、IS锁),可以提高读读并发;
  • 为了保证数据强一致,InnoDB使用强互斥锁(X锁、IX锁),保证同一行记录修改与删除的串行性;

2. 按锁的粒度来划分,可以分为:

  • 表锁:意向锁(IS锁、IX锁)、自增锁;
  • 行锁:记录锁、间隙锁、临键锁、插入意向锁;

其中

  • InnoDB的细粒度锁(即行锁),是实现在索引记录上的(我的理解是如果未命中索引则会失效);  
  • 记录锁锁定索引记录;间隙锁锁定间隔,防止间隔中被其他事务插入;临键锁锁定索引记录+间隔,防止幻读;
  • InnoDB使用插入意向锁,可以提高插入并发;
  • 间隙锁(gap lock)与临键锁(next-key lock)只在RR以上的级别生效,RC下会失效;

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • MySQL锁机制与用法分析

    本文实例讲述了MySQL锁机制与用法.分享给大家供大家参考,具体如下: MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制.比如,MyISAM和MEMORY存储引擎采用的是表级锁:BDB存储引擎采用的是页面锁,但也支持表级锁:InnoDB存储引擎既支持行级锁,也支持表级锁,但默认情况下采用行级锁. MySQL这3种锁的特性可大致归纳如下: (1)表级锁:开销小,加锁快:不会出现死锁:锁定粒度大,发生锁冲突的概率最高,并发度最低. (2)行级锁:开销大,加锁慢:会出现死锁:

  • Mysql数据库锁定机制详细介绍

    前言 为了保证数据的一致完整性,任何一个数据库都存在锁定机制.锁定机制的优劣直接应想到一个数据库系统的并发处理能力和性能,所以锁定机制的实现也就成为了各种数据库的核心技术之一.本章将对MySQL中两种使用最为频繁的存储引擎MyISAM和Innodb各自的锁定机制进行较为详细的分析. MySQL锁定机制简介 数据库锁定机制简单来说就是数据库为了保证数据的一致性而使各种共享资源在被并发访问访问变得有序所设计的一种规则.对于任何一种数据库来说都需要有相应的锁定机制,所以MySQL自然也不能例外.MyS

  • mysql中的锁机制深入讲解

    前言 为了保证数据的一致完整性,任何一个数据库都存在锁定机制.锁定机制的优劣直接应想到一个数据库系统的并发处理能力和性能,所以锁定机制的实现也就成为了各种数据库的核心技术之一. 大概几个月之前项目中用到事务,需要保证数据的强一致性,期间也用到了mysql的锁,但当时对mysql的锁机制只是管中窥豹,所以本文打算总结一下mysql的锁机制. 本文主要论述关于mysql锁机制,mysql版本为5.7,引擎为innodb,由于实际中关于innodb锁相关的知识及加锁方式很多,所以没有那么多精力罗列所有

  • 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

  • (MariaDB)MySQL数据类型和存储机制全面讲解

    1.1 数据类型概览 数据类型算是一种字段约束,它限制每个字段能存储什么样的数据.能存储多少数据.能存储的格式等.MySQL/MariaDB大致有5类数据类型,分别是:整形.浮点型.字符串类型.日期时间型以及特殊的ENUM和SET类型. 这5种数据类型的意义.限制和相关说明如下图所示: 各数据类型占用字节数,参见mariadb官方手册. 1.2 存储机制和操作方式 数据类型之所以能限定字段的数据存储长度,是因为在创建表时在内存中严格划定了地址空间,地址空间的长度是多少就能存储多少字节的数据.当然

  • 详解mysql 中的锁结构

    Mysql 支持3中锁结构 表级锁,开销小,加锁快,不会出现死锁,锁定的粒度大,冲突概率高,并发度最低 行级锁,开销小,加锁慢,会出现死锁,锁定粒度小,冲突概率最低,并发度最高 页面锁,开销和加锁处于表锁和行锁之间,会出现死锁,锁粒度基于表和行之间,并发一般 InnoDB锁问题 InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION):二是采用了行级锁.  行级锁和表级锁本来就有许多不同之处,另外,事务的引入也带来了一些新问题. InnoDB的行锁模式及加锁方法 Inn

  • Mysql中悲观锁与乐观锁应用介绍

    目录 1.锁 2.悲观锁 3.乐观锁 4.如何选择 1.锁 ​ 生活中:锁在我们身边无处不在,比如我出门玩去了需要把门锁上,比如我需要把钱放到保险柜里面,必须上锁以保证我财产的安全. 代码中:比如多个线程需要同时操作修改共享变量,这时需要给变量上把锁(syncronized),保证变量值是对的. 数据库表:当多个用户修改表中同一数据时,我们可以给该行数据上锁(行锁). sql脚本 CREATE TABLE `sys_user` ( `id` bigint(20) NOT NULL COMMENT

  • MySQL中Like概念及用法讲解

    Like中文解释为喜欢的意思,但当应用于MySQL数据库中,Like则是一种语句,用于模糊查询,主要是针对字符型字段的,在一个字符型字段列中检索包含对应子串的.本文向大家介绍MySQL中Like语句. 一.Like是什么意思 1.Like算作MySQL中的谓词,其应用与is.=.>和<等符号用法类似. 2.在sql结构化查询语言中,like语句有着至关重要的作用. 3.从某种意义上讲,Like可看作是一个精简的正则表达式功能. 二.Like作用 like语句的语法格式是 select * fr

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

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

  • 简单介绍MySQL中的事务机制

    从一个问题开始 最近银行这个事情闹的比较厉害啊,很多储户的钱放在银行,就不翼而飞了,而银行还不管不问,说是用户的责任,打官司,用户还能输了,这就是"社会主义".咱还是少发牢骚,多种树,莫谈国事. 说到银行存钱,就不得不说一下从银行取钱这件事情,从ATM机取钱这件简单的事情,实际上主要分为以下几个步骤: 登陆ATM机,输入密码: 连接数据库,验证密码: 验证成功,获得用户信息,比如存款余额等: 用户输入需要取款的金额,按下确认键: 从后台数据库中减掉用户账户上的对应金额: ATM吐出钱:

  • Tomcat和Spring中的事件机制深入讲解

    引言 最近在看tomcat源码,源码中出现了大量事件消息,可以说整个tomcat的启动流程都可以通过事件派发机制串起来,研究透了tomcat的各种事件消息,基本上对tomcat的启动流程也就有了一个整体的认识.在这一基础上,联想到之前在看spring源码过程中也存在不少事件相关知识,于是想对这两个框架中的事件派发机制做一个简单的总结,加深理解. 事件机制原理其实比较简单,抽象来看的话,设计模式中的观察者模式可以说是最经典的事件驱动机制的体现了,观察者和被观察者就体现了事件监听和事件派发的角色.还

  • 深入理解MySQL中的事务机制

    使用数据库事务可以确保除事务性单元内的所有操作都成功完成.MySQL中的InnoDB引擎的表才支持transaction.在一个事务里,如果出现一个数据库操作失败了,事务内的所有操作将被回滚,数据库将会回到事务前的初始状态.有一些不能被回滚的语句:将在本文的最后讨论. 在一个web应用中,会很经常遇到需要使用事务的地方,要么希望若干语句都执行成功,要么都不执行,如果出现有些执行成功,而其他的失败将会导致数据损坏. 在这篇文章的例子中,我们使用下面的两张表"employee"和"

随机推荐