【MySQL | 第九篇】重新认识MySQL锁

news/2024/12/22 20:20:20/

在这里插入图片描述

文章目录

  • 9.重新认识MySQL锁
    • 9.1MySQL锁概述
    • 9.2锁分类
      • 9.2.1锁的粒度
      • 9.2.2锁的区间
      • 9.2.3锁的性能
      • 9.2.4锁的级别
    • 9.3拓展:意向锁
      • 9.3.1意向锁概述
      • 9.3.2意向锁分类
      • 9.3.3意向锁作用
        • (1)意向锁的兼容互斥性
        • (2)例子1(意向锁和表级的共享/排他锁互斥)
        • (3)例子2(意向锁和行级的共享锁/排他锁兼容)
        • (4)小结

9.重新认识MySQL锁

9.1MySQL锁概述

  • 锁是计算机协调多个进程或者线程并发访问某一资源的机制
  • 在数据库中除了传统的对计算资源的争抢之外,数据也是供许多用户共享的一种资源,如何保证多线程下的数据一致性是数据库必须解决的一个问题

9.2锁分类

共有四种角度将MySQL锁分类:

  • 锁的粒度:
    • 全局锁
    • 表级锁
    • 行级锁
    • 页级锁
  • 锁的区间:
    • 间隙锁
    • 临建锁
  • 锁的性能:
    • 乐观锁
    • 悲观锁
  • 锁的级别:
    • 共享锁(读锁)
    • 排他锁(写锁/独占锁)

9.2.1锁的粒度

  • 全局锁:锁住数据库中的所有表
  • 表级锁:锁住数据库中的整张表
  • 行级锁:锁住对应的行数据

9.2.2锁的区间

  • 间隙锁

    • 定义:间隙锁用于 锁定一个范围(开区间) 而不是单个行。当事务在范围内的一行上持有锁时,其他事务无法在这个范围内插入新的数据,但是可以在范围之外插入新的数据。
    • 举例:假设一个表中的索引列有序且不重复,事务A持有了某个范围内的间隙锁,这个范围可能是一段索引范围,比如(10,20),这时其他事务无法在这个范围内插入新的行。
  • 临建锁

    • 定义::临建锁是一种结合了行锁和间隙锁的锁类型,它在锁定一个范围时同时锁定了该范围内的行以及范围之间的间隙
    • 举例:考虑一个范围查询,比如查询索引列值在(10,20)之间的行,临建锁会锁定这个范围内的行,同时锁定范围之间的间隙,防止其他事务在这个范围内插入新的行或者改变已有行的值。

9.2.3锁的性能

  • 乐观锁:

    • 定义:乐观锁认为数据在被操作时很少发生冲突,因此在访问数据时不会立即加锁,而是在更新数据时检查数据是否被其他事务修改过,如果没有则更新成功,否则进行回滚或者重试。

    • 举例:在MySQL中,可以使用乐观锁的方式是在更新数据时检查数据的版本号或者时间戳是否与当前操作一致

      UPDATE table_name 
      SET column1 = value1, version = new_version WHERE id = x AND version = old_version;
      
  • 悲观锁:

    • 定义:悲观锁认为数据在被操作时会发生冲突,因此在访问数据之前会先加锁,确保其他事务无法修改该数据,直到当前事务完成操作并释放锁。

    • 举例:在MySQL中,可以使用SELECT … FOR UPDATE语句来获取悲观锁,例如

      SELECT * 
      FROM table_name 
      WHERE condition 
      FOR UPDATE;
      

9.2.4锁的级别

  • 共享锁:

    • 定义:共享锁允许多个事务同时读取同一行数据,但阻止其他事务在该行上获取排他锁;

    • 举例:在 MySQL 中,可以使用 SELECT ... LOCK IN SHARE MODE 或者 SELECT ... FOR SHARE 来获取共享锁,例如

      SELECT * 
      FROM table_name 
      WHERE condition 
      LOCK IN SHARE MODE;
      
  • 排他锁:

    • 定义:排他锁(也称为写锁)阻止其他事务对同一行数据进行读取或写入操作,只有获取了排他锁的事务才能对数据进行修改

    • 举例:在 MySQL 中,可以使用 SELECT ... FOR UPDATE 来获取排他锁,例如

      SELECT * 
      FROM table_name 
      WHERE condition 
      FOR UPDATE;
      

9.3拓展:意向锁

9.3.1意向锁概述

MySQL 中的意向锁(Intention Lock)是一种用于管理表级锁的锁机制,用于在表级别上指示事务将要在表的哪些行上获取锁

意向锁并不是实际的锁,而是一种指示,通常用于协调事务对表级锁的获取,以提高并发性能和降低死锁的风险。

9.3.2意向锁分类

可分为两种类型:意向共享锁和意向排他锁

  • 意向共享锁(Intention Share Lock):

    • 特点:表明事务将要在表的某些行上获取共享锁。当一个事务打算获取某行的共享锁时,会在表级别请求意向共享锁
    • 作用:意向共享锁是为了协调多个事务同时获取共享锁而引入的,在获取共享锁之前,需要先检查是否存在排他锁,以防止与其他事务的排他锁冲突
  • 意向排他锁(Intention Exclusive Lock):

    • 特点:表明事务将要在表的某些行上获取排他锁。当一个事务打算获取某行的排他锁时,会在表级别请求意向排他锁
    • 作用:意向排他锁是为了协调多个事务同时获取排他锁而引入的,在获取排他锁之前,需要先检查是否存在共享锁或其他事务的排他锁,以防止与其他事务的共享锁或排他锁冲突

9.3.3意向锁作用

没有意向锁时,事务在获取表级锁/行级锁之前可能需要频繁地检查整个表,以确定是否有其他事务已经持有了排他锁或共享锁。这会增加系统的开销,降低并发性能。

举例:

事务 A 获取了某一行的排他锁,并未提交:

SELECT * FROM users WHERE id = 6 FOR UPDATE;

事务 B 想要获取 users 表的表锁(共享锁)/行级锁:

LOCK TABLES users READ;

为共享锁与排他锁互斥,所以事务 B 在视图对 users 表加共享锁的时候,必须保证:

  • 当前没有其他事务持有 users 表的排他锁。
  • 当前没有其他事务持有 users 表中任意一行的排他锁

为了检测是否满足第二个条件,事务 B 必须在确保 users表不存在任何排他锁的前提下,去检测表中的每一行是否存在排他锁

很明显这是一个效率很差的做法,但是有了意向锁之后,情况就不一样了:

(1)意向锁的兼容互斥性

特点:多个事务可以对同一张表多个意向排他锁

意向共享锁(IS)意向排他锁(IX)
意向共享锁(IS)兼容兼容
意向排他锁(IX)兼容兼容

意向锁之间是互相兼容的,虽然意向锁和自家兄弟互相兼容,但是它会与普通的排他 / 共享锁互斥

意向共享锁(IS)意向排他锁(IX)
共享锁(S)兼容互斥
排他锁(X)互斥互斥

注意:这里的排他 / 共享锁指的都是表锁!!!

意向锁不会与行级的共享 / 排他锁互斥!!!

(2)例子1(意向锁和表级的共享/排他锁互斥)

回到刚才 users 表的例子:

事务 A 获取了某一行的排他锁,并未提交:

SELECT * FROM users WHERE id = 6 FOR UPDATE;
  • 此时 users 表存在两把锁:users 表上的意向排他锁与 id 为 6 的数据行上的排他锁

事务 B 想要获取 users 表的表锁(共享锁):

LOCK TABLES users READ;
  • 此时事务 B 检测事务 A 持有 users 表的意向排他锁,就可以得知事务 A 必然持有该表中某些数据行的排他锁
  • 事务 Busers 表的加锁请求就会被排斥(阻塞),而无需去检测表中的每一行数据是否存在排他锁
(3)例子2(意向锁和行级的共享锁/排他锁兼容)
  • 意向锁并不会影响到多个事务对不同数据行加排他锁时的并发性

事务 A 获取了某一行的排他锁,并未提交:

SELECT * FROM users WHERE id = 6 FOR UPDATE;
  • 此时 users 表存在两把锁:
    • users 表上的意向排他锁
    • id 为 6 的数据行上的排他锁

事务 B 想要获取 users 表的表锁(共享锁):

LOCK TABLES users READ;
  • 此时事务 B 检测事务 A 持有 users 表的意向排他锁,就可以得知事务 A 必然持有该表中某些数据行的排他锁
  • 事务 Busers 表的加锁请求就会被排斥(阻塞),而无需去检测表中的每一行数据是否存在排他锁

最后事务 C 也想获取 users 表中某一行的排他锁

SELECT * FROM users WHERE id = 5 FOR UPDATE;
  1. 事务 C 申请 users 表的意向排他锁
  2. 事务 C 检测到事务 A 持有 users 表的意向排他锁
  3. 因为意向锁之间并不互斥,所以 事务 C 获取到了 users 表的意向排他锁
  4. 因为id 为 5 的数据行上不存在任何排他锁,最终事务 C 成功获取到了该数据行上的排他锁
(4)小结

意向锁的引入主要是为了提高并发性能。通过引入意向锁,MySQL 可以更有效地管理表级锁,减少了在并发环境下的锁冲突,从而提高了系统的并发处理能力。

在没有意向锁之前,如果一张表里面已经有行锁了此时我们再添加表锁,为了防止表锁和行锁发生冲突,表锁就需要遍历整个表中的数据检查是否有行锁。为了优化表锁检索行锁的过程,我们引入意向锁。

在这里插入图片描述


http://www.ppmy.cn/news/1452748.html

相关文章

Epinio:Kubernetes 的应用程序开发引擎-加CLI Demo演示

一、解决了什么问题? 开发人员如何专注于代码编写,怎么让他们可以完全忽略k8s基础设施并且和以前在本地Run一个应用一样的体验。 从源码构建一个容器程序 二、解决方案 Introduction | Epinio docs 三、Epinio 的 Kubernetes 的应用程序开发引擎 by Ra…

85、动态规划-零钱兑换

思路: 还是老样子,还是先使用递归方式来解,然后通过递归推动态规划。那递归如何设计? 定义一个递归方法:表示从index开始到N达到剩下的值(目标值减去上一步的值)做少可以得到数量是多少。int process(in…

【Linux】进程的隔离和控制:namespace 隔离、cgroup 控制

文章目录 五、namespace 隔离dd -- 读取、转换并输出数据mkfs -- 格式化文件系统df -- 显示文件系统磁盘使用情况mount -- 加载文件系统到指定的加载点unshare -- 创建子进程,同时与父程序不共享namespace一个 demo 六、cgroup(Control Group) 相关命令pidstat -- 监…

Python实战开发及案例分析(2)——单目标优化

在Python中,进行单目标优化主要涉及定义一个优化问题,包括一个目标函数和可能的约束条件,然后选择合适的算法来求解。Python提供了多种库,如SciPy、Pyomo、GEKKO等,用于处理各种优化问题。 案例分析:使用 …

JavaScript 中 ES6

在ES6(ECMAScript 2015)中,JavaScript引入了一些新的语法和特性来支持面向对象编程(OOP)。下面是对ES6中面向对象编程的详细解释: 类(Class): ES6引入了类的概念&#xf…

vue3 vite 路由去中心化(modules文件夹自动导入router)

通过路由去中心化可实现多人写作开发,不怕文件不停修改导致的冲突,modules中的文件可自动导入到index.js中 // 自动导入模块 const files import.meta.globEager(./modules/**.js); const modules {} for (const key in files) {modules[key.replace…

Android使用kts发布aar到JitPack仓库

Android使用kts发布aar到JitPack 之前做过sdk开发,需要将仓库上传到maven、JitPack或JCenter,但是JCenter已停止维护,本文是讲解上传到JitPack的方式,使用KTS语法,记录使用过程中遇到的一些坑.相信Groovy的方式是大家经常使用的,…

c++实战篇(三) ——对socket通讯服务端与客户端的封装

前言 在前面几篇文章中我们介绍过一些有关于网络编程的相关知识,我们介绍了在tcp传输数据的时候发送缓冲区与接收缓冲区,我们介绍了在tcp发送与接收的过程中可能出现的分包与粘包的问题: c理论篇(一) ——浅谈tcp缓存与tcp的分包与粘包 我们介绍了在网络…