mysql锁机制详解(代码片段)

minikobe minikobe     2023-04-24     127

关键词:

前言

  大概几个月之前项目中用到事务,需要保证数据的强一致性,期间也用到了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锁)、自增锁;
  • 行锁:记录锁、间隙锁、临键锁、插入意向锁;

  其中

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

转载:https://www.cnblogs.com/volcano-liu/p/9890832.html

mysql中的锁机制详解(代码片段)

...大麦锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的计算资源(如CPU、RAM、I/O等)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须... 查看详情

mysql基础篇(06):事务管理,锁机制案例详解(代码片段)

...GitHub·点这里||GitEE·点这里一、锁概念简介1、基础描述锁机制核心功能是用来协调多个会话中多线程并发访问相同资源时,资源的占用问题。锁机制是一个非常大的模块,贯彻MySQL的几大核心难点模块:索引,锁机制,事务。这... 查看详情

mysql死锁过程及案例详解之用户自定义锁(代码片段)

...接到数据库时,能保证同类查询执行时不相互冲突的机制即是锁。比如马路上的信号灯就是一个解决冲突的例子,在一定的时间内锁定了能通行的方向或者路线。MySQL里的锁实际上是一个处于处于授予或挂起状态锁请求。... 查看详情

重新学习mysql数据库7:详解myisam与innodb引擎的锁实现(代码片段)

...新学习Mysql数据库7:详解MyIsam与InnoDB引擎的锁实现说到锁机制之前,先来看看Mysql的存储引擎,毕竟不同的引擎的锁机制也随着不同。三类常见引擎: MyIsam:不支持事务,不支持外键,所以访问速度快。锁机制是表锁,支持... 查看详情

详解mysql中的锁机制

锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的计算资源(如CPU、RAM、I/O等)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决... 查看详情

mysql各种锁机制(代码片段)

阅读目录一、mysql锁介绍锁来源锁种类思维导图一览二、MyISAM表锁sys_admin_log操作日志MyISAM表test_users用户InnoDB表1、读锁2、写锁3、总结意向锁含义(百度百科)总结三、InnoDB行锁1、共享锁(S锁)2、排它锁(X锁... 查看详情

mysql锁机制(代码片段)

文章目录概述1锁的粒度2锁的实现2.1MyISAM锁的实现2.1.1MySQL表锁2.1.2MyISAM加锁方式2.1.3写阻塞读2.1.4读阻塞写2.2InnoDB锁的实现2.2.1InnoDB行锁2.2.2行锁加锁方式2.2.3行锁实现方式2.2.4意向锁2.2.5间隙锁(GapLocks)2.2.6临键锁(Next-KeyLocks)2.2.7自增... 查看详情

mysql中的锁机制(代码片段)

介绍锁机制技术是为了解决问题而生的,锁被用来实现隔离性,保证并发事务的正确性。两段锁&一次封锁两段锁数据库遵循的是两段锁协议,将事务分成两个阶段,加锁阶段和解锁阶段(所以叫两段锁)加锁阶段:在加锁阶... 查看详情

java中线程同步机制synchronized,互斥锁,死锁,释放锁的详解(代码片段)

...享一下给大家,👉点击跳转到网站一、线程同步机制synchronized的理解二、synchronized的具体使用下面可以通过同步机制,解决多线程卖票,出现的超卖问题,代码如下publicclassSellTic 查看详情

mysql加锁过程详解-innodb下的记录锁,间隙锁,next-key锁(代码片段)

Mysql加锁过程详解(1)-基本知识Mysql加锁过程详解(2)-关于mysql幻读理解Mysql加锁过程详解(3)-关于mysql幻读理解Mysql加锁过程详解(4)-selectforupdate/lockinsharemode对事务并发性影响Mysql加锁过程详解(5)-innodb多版本并发控制原... 查看详情

mysql锁机制(代码片段)

innodb的锁分为共享锁和排它锁。这跟myisam中的读锁和写锁有很多不同,也是大多数人容易混淆的地方。myisam中的两种锁默认都是存储引擎自己加上去的(当然自己手动加也可以),查询时即(加了读锁之后ÿ... 查看详情

python进阶篇:mysql锁详解(篇幅较长,请耐心)(代码片段)

...解决并发情况下多线程/进程造成数据不一致问题的一种机制。通过锁来保证数据的一致性。但是锁也很大程度影响了数据库并发的效率。2,InnoDB中的锁​以下是innodb中的锁:SharedandExclusiveLocksIntentionLocksRecordLocksGapLocksNext-KeyLoc... 查看详情

python进阶篇:mysql锁详解(篇幅较长,请耐心)(代码片段)

...解决并发情况下多线程/进程造成数据不一致问题的一种机制。通过锁来保证数据的一致性。但是锁也很大程度影响了数据库并发的效率。2,InnoDB中的锁​以下是innodb中的锁:SharedandExclusiveLocksIntentionLocksRecordLocksGapLocksNext-KeyLoc... 查看详情

mysql锁机制表锁和行锁详解

锁的分类:从对数据操作的类型(读写)分:读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响写锁(排它锁):当前写操作没有完成前,它会阻断其他锁... 查看详情

mysql锁的分类和加锁机制(代码片段)

...不同语句加锁的属性三、隔离级别对加锁的影响四、上锁机制五、意向锁在了解MySQL锁之前,首先我们必须要明白加锁的是为了解决什么问题。我们知道事务具有个隔离性的特性,而隔离性的实现主要就是通过锁以及MVCC... 查看详情

python进阶篇:mysql锁详解(篇幅较长,请耐心)(代码片段)

即上篇《Python进阶篇:MySQL隔离级别详解》感觉有必要讲清楚mysql是如何在可重复读解决了幻读问题,这篇锁详解可以结合事务一起看。目录1,什么是锁?2,InnoDB中的锁3,锁的颗粒度与效率4,共享锁... 查看详情

详解mysql复制机制--异步复制,半同步复制和并行复制(代码片段)

详解MySQL复制机制--异步复制,半同步复制和并行复制**#异步复制异步复制是MySQL自带的最原始的复制方式,主库和备库成功建立复制关系后,在备库上会有一个IO线程去主库拉取binlog,并将binlogx到本地,就是下图中Relaylog,然后... 查看详情

mysql&innodb锁机制全面解析(代码片段)

这里写目录标题一、前言二、锁的类型2.1全局锁2.2表级锁2.2.1表锁2.2.2元数据锁(MetaDataLocks)2.2.3自增列锁(AUTO-INCLocks)2.2.4意向锁(IntentionLocks)2.3行级锁2.3.1RecordLocks2.3.2GapLocks2.3.3Next-KeyLo 查看详情