首页 > 数据库 >【22.0】MySQL进阶知识之锁机制

【22.0】MySQL进阶知识之锁机制

时间:2024-01-29 21:56:36浏览次数:32  
标签:insert 之锁 事务 进阶 死锁 t1 索引 22.0 values

【一】什么是锁机制

  • 我们可以通过一个很简单的比喻来理解事务的锁机制。
  • 比如同一个办公室的同事们
    • 都想使用打印机打印文件
      • 如果不加以控制
      • 可能出现两个人同时打印不同的内容在一个文件里
      • 就会引起内容混乱。
    • 于是,我们就引入了锁的概念
      • 当有并发的多个事务同时操作同一份数据时
      • 只有“抢到”了锁的事务
      • 才能真正去操作数据
      • 使得数据的安全性得到保证。

【二】为什么要用锁机制

  • 锁保证并发的多个事务同一时间只有一个能运行
    • 会一定程度上降低程序的运行效率
    • 但是能大大提升数据的安全性。

【三】数据库锁的分类

【1】按粒度分

  • 数据库的锁按粒度分为
    • 行级锁
    • 表级锁
    • 页级锁

(1)什么是⾏级锁

  • ⾏级锁是Mysql中锁定粒度最细的⼀种锁

    • 表示只针对当前操作的⾏进⾏加锁。
  • ⾏级锁能⼤⼤减少数据库操作的冲突。

    • 其加锁粒度最⼩,但加锁的开销也最⼤。
  • ⾏级锁分为共享锁和排他锁。

(2)⾏级锁的特点

  • 开销⼤,加锁慢;
  • 会出现死锁;
  • 锁定粒度最⼩,发⽣锁冲突的概率最低,并发度也最⾼

(3)⾏级锁解释

  • 由于数据库的库和表都是事先建好的

    • 所以我们针对数据库的操作一般都是针对记录。
    • 而对记录进行的四种操作(增删改查)
    • 我们可以分为两类
      • 增删改属于读操作
      • 而查询属于写操作。
  • 写操作默认就会加锁,且加的是互斥锁

    • 很容易理解,在进行写行为的时候一定是必须“排他”的。
    • 读操作默认不受任何锁影响
    • 但是互斥锁和共享锁都可以加。
  • 读操作加互斥锁 for update;

  • 读操作加共享锁 lock in share mode;

提示:关于共享锁和互斥锁,我们将在下一小节更详细地讲述

(4)行级锁锁的是索引

  • 行级锁锁的是索引
    • 命中索引以后才会锁行
    • 如果没有命中索引
    • 会把整张表都锁起来。
  • 命中主键索引就锁定这条语句命中的主键索引
    • 命中辅助索引就会先锁定这条辅助索引
    • 再锁定相关的主键索引
    • 考虑到性能,innodb默认支持行级锁
    • 但是只有在命中索引的情况下才锁行,
  • 否则锁住所有行
    • 本质还是行锁
    • 但是此刻相当于锁表了

(5)行级锁的三种算法

  • 1、Record lock

  • 2、Gap lock

  • 3、Next-key lock

  • 其中 Next-key lock 为MySQL默认的锁机制

    • 相当于另外两种锁的功能的整合
    • 并能够解决幻读问题。
  • 提示:

    • 在RR事务隔离机制下,才会锁间隙
    • 而RR机制是mysql的默认事务隔离机制。
    • 所以,在默认情况下,其实innodb存储引擎锁的是行以及间隙.
  • 我们可以用一个实验来验证上述关于行锁的结论

(6)实验

事务一 事务二
start transaction; 开启事务start transaction;
-- 加排他锁select from t1 where id=7 for update; -- 须知-- 1、上述语句命中了索引,所以加的是行锁-- 2、InnoDB对于行的查询都是采用了Next-Key Lock的算法,锁定的不是单个值,而是一个范围(GAP)表记录的索引值为1,5,7,11,其记录的GAP区间如下:(-∞,1],(1,5],(5,7],(7,11],(11,+∞)因为记录行默认就是按照主键自增的,所以是一个左开右闭的区间其中上述查询条件id=7处于区间(5,7]中,所以Next-Key lock会锁定该区间的记录,但是还没完-- 3、*InnoDB存储引擎还会对辅助索引下一个键值加上gap lock**。区间(5,7]的下一个Gap是(7,11],所以(7,11]也会被锁定综上所述,最终确定5-11之间的值都会被锁定
-- 下述sql全都会阻塞在原地insert t1 values(5);insert t1 values(6);insert t1 values(7);insert t1 values(8);insert t1 values(9);insert t1 values(10); -- 下述等sql均不会阻塞insert t1 values(11); insert t1 values(1); insert t1 values(2);insert t1 values(3);insert t1 values(4);
-- 提交一下事务,不要影响下一次实验commit; -- 提交一下事务,不要影响下一次实验commit;

【2】按级别分

  • 数据库的锁按级别分为

    • 共享锁,排他锁,共享锁
    • 又被称作读锁,s锁
      • 含义是多个事务共享同一把锁
      • 其中每个事务都能访问到数据
      • 但是没有办法进行修改。
  • 注意:

    • 如果事务T对数据A加上共享锁后
    • 则其他事务只能对A再加共享锁或不加锁(在其他事务里一定不能再加排他锁
    • 但是在事务T自己里面是可以加的)
  • 排他锁又被称作互斥锁,写锁,x锁

    • 含义是如果有一个事务获取了一个数据的排他锁
    • 那么其它的事务都无法再次获得该数据的任何锁了
    • 但是排他锁支持文件读取,修改和写入。

【3】按使用方式分

  • 数据库的锁按使用方式分为
    • 悲观锁、乐观锁

(1)悲观锁(Pessimistic Locking)

  • 顾名思义指的是对外界将要进行的数据修改操作持悲观态度
  • 因此,在整个数据处理过程中,将数据处于锁定状态。
  • 现在由于互联网的高并发架构,即使加上悲观锁也无法保证数据不被外界修改,因此不推荐使用。

(2)乐观锁(Optimistic Locking)

  • 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突
  • 所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测
  • 如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。
  • 通常乐观锁的实现是在表中加一个字段(可能是时间戳或版本号)
  • 在写入的时候会查询一下版本号
    • 如果版本号没有改变,就写入数据库并同时改变版本号。
  • 从本质上来说,乐观锁并没有加锁
    • 所以效率会大大提升
    • 但也有一定的缺陷,就是可能导致一部分任务的写入失败。

【四】死锁问题

  • 我们举一个例子来形象的说明死锁这个概念。
  • 比如你和你的邻居同时被锁在了屋子里
    • 然而你有你邻居的钥匙
    • 你的邻居也有你的钥匙
    • 你们互相可以打开对方的房门
    • 但是却都被锁在了各自的屋子里
    • 这就是一个简单的死锁现象

【1】第一种情况的死锁

事务1 事务2
begin begin
select * from t1 where id=6 for update; delete from t1 where id=3;
update t1 set age=18 where id=3; delete from t1 where id=6; -- 阻塞
  • 第一种死锁情况非常好理解,也是最常见的死锁
    • 每个事务执行两条SQL,分别持有了一把锁
    • 然后加另一把锁,产生死锁。
  • 大多数死锁问题
    • innodb存储引擎都会发现并抛出异常
    • 但是有一种死锁问题极其隐蔽。

【2】第二种情况的死锁

  • 与上一种死锁情况不同的是
    • 这种死锁现象必须是两个事务同时运行的情况下才可能发生。
  • 前面我们提到过,聚集索引对应的是一整行数据记录。
    • 当事务1根据一定的过滤条件
    • 筛选出两条辅助索引时
    • 根据索引的有序性
    • 在锁完辅助索引后锁主键索引时
    • 先锁主键1对应的记录再锁主键2。
    • 如果在此同时
      • 事务2通过别的辅助索引同样访问到了这两条数据
      • 但顺序却是先锁主键2再锁主键1
      • 就会互相锁住
      • 产生死锁现象
      • 而且这种情况非常隐蔽,较难排查。

标签:insert,之锁,事务,进阶,死锁,t1,索引,22.0,values
From: https://www.cnblogs.com/dream-ze/p/17995447

相关文章

  • 【21.0】MySQL进阶知识之事务隔离机制
    【一】数据库读现象的本质是数据库在高并发场景下多个同时执行的事务带来的影响。【二】数据库三大读现象在数据库中,不同的事务隔离级别可能会导致脏读(DirtyRead)、不可重复读(Non-repeatableRead)和幻读(PhantomRead)等问题的出现。【1】脏读(1)概述事务1和事务2并发执行......
  • Unity架构师进阶:红点系统的架构与设计
    面试的时候经常被问道如何来设计一个红点系统,本文将详细地介绍如何设计一个红点系统,有哪些接口,并完整地给出实现。红点系统的需求分析首先我们来分析一下红点系统的设计需求:红点系统严格意义上来说不属于框架,而是游戏逻辑,所以代码不要放到通用的框架里面,并不属于基础服务。它......
  • INFINI Labs 产品更新 | 统一版本号 1.22.0
    INFINILabs产品又更新啦~,包括Console,Gateway,Loadgen,Agent1.22.0。为了避免版本不同带来的困扰,以后发布均统一版本号,此次版本重点修复历史遗留Bug、优化内存占用等。以下是本次更新的详细说明。INFINIConsolev1.22.0INFINIConsole是一款非常轻量级的多集群、跨版本的搜索......
  • INFINI Labs 产品更新 | 统一版本号 1.22.0
    INFINILabs产品又更新啦~,包括Console,Gateway,Loadgen,Agent1.22.0。为了避免版本不同带来的困扰,以后发布均统一版本号,此次版本重点修复历史遗留Bug、优化内存占用等。以下是本次更新的详细说明。INFINIConsolev1.22.0INFINIConsole是一款非常轻量级的多集群、跨版本的搜......
  • C# 面向对象编程进阶:构造函数详解与访问修饰符应用
    C#构造函数构造函数是一种特殊的方法,用于初始化对象。构造函数的优势在于,在创建类的对象时调用它。它可以用于为字段设置初始值:示例获取您自己的C#服务器创建一个构造函数://创建一个Car类classCar{publicstringmodel;//创建一个字段//为Car类创建一个......
  • C# 面向对象编程进阶:构造函数详解与访问修饰符应用
    C#构造函数构造函数是一种特殊的方法,用于初始化对象。构造函数的优势在于,在创建类的对象时调用它。它可以用于为字段设置初始值:示例获取您自己的C#服务器创建一个构造函数://创建一个Car类classCar{publicstringmodel;//创建一个字段//为Car类创建一......
  • 【C语言进阶篇】模拟实现通讯录 (内附源码)
    (文章目录)......
  • Python并发编程之锁
    锁【一】同步原语操作系统—同步原语-CSDN博客实现互斥锁的并发程序设计-皮特森算法【Peterson算法-维基百科】​ 同步原语是一组用于协调多个执行线程或进程之间操作顺序和共享资源访问的基本机制。这些机制的目的是确保多个执行单元能够按照某种协调方式执行,以避免并发......
  • Trie树学习笔记+杂题(进阶1 Trie)
    前言:回来上课吧,不然真的就没人了。现在也是没有脑子一、Trie树学习笔记+杂题(进阶1Trie)相关题单:戳我1.trie树简介字典树,英文名trie。顾名思义,就是一个像字典一样的树,核心原理就是用空间换时间,利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,所以它可以处......
  • Trie树学习笔记+杂题(进阶1 Trie)
    前言:回来上课吧,不然真的就没人了。现在也是没有脑子一、Trie树学习笔记+杂题(进阶1Trie)相关题单:戳我1.trie树简介字典树,英文名trie。顾名思义,就是一个像字典一样的树,核心原理就是用空间换时间,利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,所以它可以处......