MySQL 锁机制

2023-09-20 16:06:13

1. 锁是什么?

        是为了保证数据并发访问时的一致性和有效性,数据库提供的一种机制。锁机制的优劣直接影响到数据库的并发处理能力和系统性能,所以锁机制也就成为了各种数据库的核心技术之一。同时,锁机制也为实现 MySQL事务的各个隔离级别提供了保证。

2. 锁的缺点

        锁是一种消耗资源的机制,想要实现锁的各种操作,包括获得锁检测锁是否已解除释放锁等 ,都会增加系统的开销。

3. 锁的分类

        为了尽可能提高数据库的并发量,每次锁定的数据范围越小越好,但是锁定越小的范围,耗费的系统资源越多,也会系统性能下降。所以,为在高并发响应和系统性能两方面进行平衡,这样就产生了“锁粒度”的概念,可以将锁粒度理解成锁定范围。

那么根据锁的粒度MySQL细分了如下三种锁:表级锁、行级锁、页级锁

3.1. 表级锁(table lock)

        表级锁是一种表级别的锁定机制,是 MySQL最大颗粒度的锁定机制,它会锁定整张表,但同时可以很好的避免死锁。

MyISAM存储引擎默认使用表级锁。

表级锁根据操作的不同,分为:读锁(共享锁)、写锁(排他锁)。

3.1.1.读锁(read lock

        也叫共享锁(shared lock),一个用户在对表进行读操作(select)时, 针对同一份数据,多个读操作可以同时进行而不会互相影响。

3.1.2.写锁(write lock

        也叫排他锁(exclusive lock),一个用户在对表进行写操作(插入、删除、更新等)时,需要先获得写锁,它会阻塞其它用户对该表的所有读写操作,具备排他性

小结:        1.读锁会阻塞写操作,不会阻塞读操作        2.写锁会阻塞读和写操作

3.1.3.表级锁的优点和缺点

  1. 对整张表加锁
  2. 开销小
  3. 加锁快
  4. 无死锁
  5. 锁粒度大,发生锁冲突概率大,并发性低

3.2. 行级锁(row lock)

        行级锁的锁定颗粒度在 MySQL 中是最小的,只针对操作的当前行进行加锁,所以行级锁发生锁定资源争用的概率也最小。

        由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要处理并发逻辑更多,同时消耗的资源也就更大。此外,行级锁也最容易发生死锁。所以说行级锁最大程度地支持并发处理的同时,也带来了最大的锁开销。

InnoDB 存储引擎默认使用行级锁。

        行级锁根据操作的不同,分为:读锁(共享锁 S)、写锁(排他锁 X)、意向共享锁IS)、意向排它锁IX)。

3.2.1.意向共享锁IS

一个事务给一个数据行加共享锁时,必须先获得该表的意向共享锁,简称IS锁。

3.2.2.意向排他锁IX

一个事务给一个数据行加排他锁时,必须先获得该表的意向排他锁,简称IX锁。

3.2.3.行级锁的优点和缺点

  1. 对一行数据加锁
  2. 开销大
  3. 加锁慢
  4. 会出现死锁
  5. 锁粒度小,发生锁冲突概率最低,并发性高

3.3. 页级锁(page lock)

页级锁是 MySQL 中比较独特的一种锁定级别。
页级锁的颗粒度介于行级锁与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力同样也是介于上面二者之间。另外,页级锁和行级锁一样,会发生死锁。
页级锁主要应用于 BDB 存储引擎。

3.4. 行级锁的实现算法

        在 MySQLInnoDB存储引擎中,行锁通过给之前索引内容的索引树中的索引项加锁来实现,如果没有索引,InnoDB 将通过隐藏的主键索引(聚集索引)引来对记录加锁。

InnoDB 主要通过以下 3 种算法实现行级锁:

  • 记录锁Record Lock):直接对索引项加锁,属于单个行记录上的锁。Record Lock总是会去锁住索引记录,如果InnoDB存储引擎表建立的时候没有设置任何一个索引,这时InnoDB存储引擎会使用隐式的主键来进行锁定。
  • 间隙锁Gap Lock):间隙锁是一个在索引记录之间的间隙上进行锁定。间隙可以是两个索引记录之间,也可能是第一个索引记录之前或最后一个索引之后的空间。间隙锁会锁定该间隙空间,防止其它事务在这个区域内插入、修改、删除数据;
  • 临键锁(Next-Key Lock):记录锁+间隙锁组合起来用就叫做临键锁 Next-Key Lock。 锁定一个范围,同时包含记录本身。记录锁只能锁住已经存在的记录,为了避免插入新记录,需要依赖间隙锁。

小结:

4. 锁的兼容与互斥

锁和锁之间的关系,要么是兼容的,要么是互斥的。

  • a 和锁 b 兼容是指:操作同样一组数据时,如果事务 t1 获取了锁 a,另一个事务 t2 还可以获取锁 b
  • a 和锁 b 互斥是指:操作同样一组数据时,如果事务 t1 获取了锁 a,另一个事务 t2 t1 释放锁 a 之前无法释放锁 b

        如果一个事务请求的锁模式与当前的锁兼容,InnoDB 就将请求的锁授予该事务;反之,如果两者不兼容,该事务就要等待锁释放。

5. 乐观锁与悲观锁

5.1.乐观锁(Optimistic Lock)

        顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于读多写少的应用场景。

5.2.悲观锁(Pessimistic Lock)

        悲观锁(又名“悲观并发控制”,Pessimistic Concurrency Control,缩写“PCC”)是一种并发控制的方法。它可以阻止一个事务以影响其他用户的方式来修改数据。如果一个事务执行的操作读某行数据应用了锁,那只有当这个事务把锁释放,其他事务才能够执行与该锁冲突的操作。

        所以,顾名思义就是很悲观的锁定思想,每次去拿数据的时候都认为其它的事务会修改,所以每次在拿数据的时候都会上锁,这样其它事务想要获取这个数据就会被block阻塞,直到当前事务释放锁。关系型数据库中的行锁,表锁,读锁,写锁等,都是在做操作之前先上锁。它指的是对数据被外界修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。

        悲观锁主要用于数据争用激烈的环境,以及发生并发冲突时使用锁保护数据的成本低于回滚事务的成本的环境中。

5.3.两种锁的优缺点:

  •         乐观锁适用于写比较少的情况下,即:并发冲突相对较低的场景。这样可以省去了锁的开销,加大了系统的整个吞吐量。
  •         悲观锁适用于写入比较多的情况下,因为如果经常产生数据冲突,使用乐观锁,应用程序会不断的retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。

6. 死锁

        数据库的死锁是指两个或两个以上的事务在执行过程中,因争夺资源而造成的一种互相等待的现象。常见的报错信息为“Deadlock found when trying to get lock...”。

        死锁发生以后,只有部分或完全回滚其中一个事务,才能打破死锁。多数情况下只需要重新执行因死锁回滚的事务即可。

所以在实际应用中,通常可以使用的避免死锁的办法:

  1. 如果不同程序会并发存取多个表,或者涉及多行记录时,尽量约定以相同的顺序访问表,这样可以大大降低死锁的发生。例如:事务1和2都请求需要请求资源A,B,那么顺序最好保持一致AB或者BA,一个AB,一个BA,则死锁概率会大大提升。
  2. 业务中要及时提交或者回滚事务,可减少死锁产生的概率。
  3. 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率。
  4. 对于非常容易产生死锁的部分,可以尝试升级锁粒度,表级锁不会产生死锁。

更多推荐

【苹果】SpringBoot监听Iphone15邮件提醒,Selenium+Python自动化抢购脚本

前言🍊缘由Iphone15来了,两年之约你还记得吗?两年前,与特别的人有一个特别的约定。虽物是人非,但思念仍在。遂整合之前iphone13及iphone14的相关抢购代码,完成一个SpringBoot监听Iphone15有货邮件提醒+python自动化脚本小功能。后端基于SpringBoot,通过苹果官网进行有货接口

Vue.js vs React:哪一个更适合你的项目?

🌷🍁博主猫头虎(🐅🐾)带您GotoNewWorld✨🍁🦄博客首页——🐅🐾猫头虎的博客🎐🐳《面试题大全专栏》🦕文章图文并茂🦖生动形象🐅简单易学!欢迎大家来踩踩~🌺🌊《IDEA开发秘籍专栏》🐾学会IDEA常用操作,工作效率翻倍~💐🌊《100天精通Golang(基础入门篇)》🐅学会Gol

Spring Cloud实战案例 │ Apollo和Zuul的整合开发

Apollo是携程研发的开源配置管理中心,能够集中管理应用于不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性。本案例结合一个案例介绍Apollo和Zuul的整合开发。整个应用分为4个微服务项目,分别是Eureka服务器项目mweathereurekaserver、服务提供者项

OpenSergo & Spring Cloud Alibaba 带来的服务治理能力

博主介绍:✌全网粉丝3W+,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验✌博主作品:《Java项目案例》主要基于SpringBoot+MyBatis/MyBatis-plus+MySQL+Vue等前后端

云原生微服务 第四章 Spring Cloud Netflix 之 Eureka

系列文章目录第一章Java线程池技术应用第二章CountDownLatch和Semaphone的应用第三章SpringCloud简介第四章SpringCloudNetflix之Eureka文章目录系列文章目录@[TOC](文章目录)前言1、Eureka两大组件2、Eureka服务注册与发现3、案例3.1、创建主工程3.

jq命令安装与使用

目录一、简介二、下载及安装1.Linux安装2.Windows安装3.测试安装结果三、jq用法1.基本语法2.常见用法1)格式化JSON2)获取属性3)属性不存在情况处理4)数组遍历、截取、展开5)管道、逗号、加号6)数据构造7)基础函数8)过滤、排序、分组函数9)字符串操作函数10)日期函数11)高级用法官网地址:h

网络安全(黑客技术)学习笔记

1.网络安全是什么网络安全可以基于攻击和防御视角来分类,我们经常听到的“红队”、“渗透测试”等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。2.网络安全市场一、是市场需求量高;二、则是发展相对成熟入门比较容易。3.所需要的技术水平需要掌握的知识点偏多(举例):外围打点能力渗透漏洞挖掘流量分析代

LLM系列 | 20 : Llama2 实战(下篇)-中文语料微调(附完整代码)

简介紧接前文:万字长文细说ChatGPT的前世今生Llama2实战(上篇):本地部署(附代码)上篇主要介绍Llama2的基本情况和基于官方模型实测Llama2在中英上的效果,包括单轮和多轮对话。今天这篇小作文作为Llama2的下篇,主要介绍如何用中文语料对Llama2的基座模型(7B版)进行微调并实测微调后模型的效果。

八大排序(一)冒泡排序,选择排序,插入排序,希尔排序

一、冒泡排序冒泡排序的原理是:从左到右,相邻元素进行比较。每次比较一轮,就会找到序列中最大的一个或最小的一个。这个数就会从序列的最右边冒出来。以从小到大排序为例,第一轮比较后,所有数中最大的那个数就会浮到最右边;第二轮比较后,所有数中第二大的那个数就会浮到倒数第二个位置……就这样一轮一轮地比较,最后实现从小到大排序。代

面试题五:computed的使用

题记大部分的工作中使用computed的频次很低的,所以今天拿出来一文对于computed进行详细的介绍,因为Vue的灵魂之一就是computed。模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护,所以,对于复杂逻辑,vue提倡使用计算属性。需要特别说明:计算属性

python基础语法回顾

1/1pythoneval函数1/1eval()函数是Python中的一个内置函数,它用于执行一个字符串形式的Python表达式,并返回表达式的结果。这个函数接受一个字符串参数,然后将其解析并执行,将结果返回。通常情况下,eval()用于动态地执行Python代码。以下是eval()函数的基本语法:pythonresu

热文推荐