数据库中的六大锁

目录

一、死锁

二、锁的区间划分

1、间隙锁(Gap Locks)

2、临键锁(Next-key Locks)

三、锁的粒度划分

1、表级锁(Table-level lock)

2、行级锁(Record Locks)

3、页级锁

四、锁级别划分

1、共享锁(share lock,即S锁)

2、排它锁 / 独占锁(exclusive lock,即X锁)

3、意向锁

五、加锁方式分类

1、自动锁( Automatic Locks)

2、显示锁(LOCK TABLES )

六、锁的使用方式分类

1、乐观锁(Optimistic Lock)

2、悲观锁(Pessimistic Lock)

总结


锁是计算机协调多个进程或线程并发访问某一个资源的机制,在数据库中,除传统的计算资源(CPU、RAM、I/O)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所在有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。

一、死锁

讲述之前先简单介绍第一个锁:死锁
如下表

CREATE TABLE `test` (`id` int(20) NOT NULL,`name` varchar(20) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

表中数据有:

mysql> SELECT * FROM test;
+----+------+
| id | name |
+----+------+
|  1 | 1    |
|  5 | 5    |
+----+------+
6 rows in set (0.00 sec)

两个事务对一个表进行如下操作

session1										 	session2
begin;										 	 	begin;select * from test where id = 3 for update;     	select * from test where id = 4 for update;insert into test(id, name) values(3, "test1");    insert into test(id, name) values(4, "test2");锁等待中
锁等待解除死锁,session 2的事务被回滚


上面两个并发事务一定会发生死锁(这里之所以限定RR和Serializable两个隔离级别,是因为只有这两个级别下才会有间隙锁/临键锁,而这是导致死锁的根本原因)。
select … for update虽然可以用于解决数据库的并发操作,但在实际项目中却不建议使用,原因是当查询条件对应的记录不存在时,很容易造成死锁。而造成死锁的原因和MySQL的锁机制有关。

二、锁的区间划分

1、间隙锁(Gap Locks)

实例: (3, 4)
间隙锁是开区间的,是一个在索引记录之间的间隙上的锁。
作用:保证某个间隙内的数据在锁定情况下不会发生任何变化。比如我mysql默认隔离级别下的可重复读(RR)。
当使用唯一索引来搜索唯一行的语句时,不需要间隙锁定。如下面语句的id列有唯一索引,此时只会对id值为10的行使用记录锁。

select * from t where id = 10 for update;// 注意:普通查询是快照读,不需要加锁

如果,上面语句中id列没有建立索引或者是非唯一索引时,则语句会产生间隙锁。

如果,搜索条件里有多个查询条件(即使每个列都有唯一索引),也是会有间隙锁的。
根据检索条件向下寻找最靠近检索条件的记录值A作为左区间,向上寻找最靠近检索条件的记录值B作为右区间,即锁定的间隙为(A,B),并且,不允许其他区间进行修改的值为查询的值

2、临键锁(Next-key Locks)

临键锁是行锁+间隙锁,即临键锁是是一个左开右闭的区间,比如(- ∞, 1 ] |(1, 3 ] |(3, 4 ] | (4, + ∞)。
InnoDB的默认事务隔离级别是RR,在这种级别下,如果使用select … in share mode或者select … for update语句,那么InnoDB会使用临键锁,因而可以防止幻读;但即使你的隔离级别是RR,如果你这是使用普通的select语句,那么InnoDB将是快照读,不会使用任何锁,因而还是无法防止幻读。

三、锁的粒度划分

1、表级锁(Table-level lock)

直接给整个表添加锁:

select * from student where name = 'tom' for update

InnoDB在使用过程中只要不通过索引检索数据时,全部是表锁。
开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低
MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此用户一般不需要直接用LOCK TABLE命令给MyISAM表显式加锁。

2、行级锁(Record Locks)

InnoDB中给指定的行添加锁:

select * from student where id > 10 for update
1
InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点,MySQL于Oracle不同,后者是通过在数据块中对相应的数据行加锁来实现的,InnoDB只有通过索引条件检索数据,InnoDB才使用行级锁
行锁的劣势:开销大;加锁慢;会出现死锁
行锁的优势:锁的粒度小,发生锁冲突的概率低;处理并发的能力强

3、页级锁

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

四、锁级别划分

1、共享锁(share lock,即S锁)

共享锁(S):又称读锁,允许一个事务去读取一行,阻止其他事务获得相同数据集的排它锁,若事务T对数据对象A加上S锁,则事务T可以读A,但不能修改A,其他事务只能对再对A加S锁,而不能加X锁,直到T释放A上的锁,这保证了其他事务可以读A,但在释放A上的S锁之前不能对A做任何修改。

2、排它锁 / 独占锁(exclusive lock,即X锁)

排它锁(X):又称写锁,允许获取排它锁的事物更新数据,阻止其他事务取得相同的数据集共享读锁和排它写锁,若事务T对数据对象A加上X锁,事物T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T 释放A上的锁

3、意向锁

事物B对一行数据使用行锁,当有另一个事物A对这个表使用了表锁,那么这个行锁就会升级为表锁,事务A在申请行锁(写锁)之前,数据库会自动先给事务A申请表的意向排他锁。当事务B去申请表的写锁时就会失败,因为表上有意向排他锁之后事务B申请表的写锁时会被阻塞。
当一个事务在需要获取资源的锁定时,如果该资源已经被排他锁占用,则数据库会自动给该事务申请一个该表的意向锁。如果自己需要一个共享锁定,就申请一个意向共享锁。如果需要的是某行(或者某些行)的排他锁定,则申请一个意向排他锁。

五、加锁方式分类

1、自动锁( Automatic Locks)

当进行一项数据库操作时,缺省情况下,系统自动为此数据库操作获得所有有必要的锁。

自动锁分为三种:
DML 锁:

  • 锁用于控制并发事务中的数据操纵,保证数据的一致性和完整性。
  • 保护并发情况下的数据完整性。
  • 语句能够自动地获得所需的表级锁(TM)与行级(事务)锁(TX)。

DDL 锁:

  • 锁用于保护数据库对象的结构,如表、索引等的结构定义。

排它 DDL 锁

  • 创建、修改、删除一个数据库对象的 DDL 语句获得操作对象的 排它锁。

共享 DDL 锁

  • 需在数据库对象之间建立相互依赖关系的 DDL 语句通常需共享获得 DDL锁。
  • 如创建一个包,该包中的过程与函数引用了不同的数据库表,当编译此包时该事务就获得了引用表的共享 DDL 锁。如使用 alter table 语句时,为了维护数据的完成性、一致性、合法性,该事务获得一排它 DDL 锁

systemlocks。

2、显示锁(LOCK TABLES )

某些情况下,需要用户显示的锁定数据库操作要用到的数据,才能使数据库操作执行得更好,显示锁是用户为数据库对象设定的。
(1) LOCK TABLES

LOCK TABLES  tbl_name  read|write, tbl_name read|write, ...UNLOCK TABLES #解开全部的锁,后面不跟表名


施加写锁,写锁是排他的,不允许别的线程读和写,自己施加锁是不受影响
(2) FLUSH TABLES:将内存中的数据同步到磁盘上,即刷写操作,但是这个同步过程可以施加锁,一旦施加锁的时候,即执行将对应的表同步,关闭,打开,并施加锁。一旦施加了锁,此时别的线程读操作不受影响,但是写操作将不能被执行,需要解锁后才能生效

FLUSH TABLES tbl_name,... [WITH READ LOCK];UNLOCK TABLES;锁住所有的表,注意,可以针对某张表进行上锁MariaDB [sunny]> flush tables with read lock;Query OK, 0 rows affected (0.00 sec)其他线程,解锁后才能够插入数据MariaDB [sunny]> insert into classlist values ("tracy",2,"99");Query OK, 1 row affected (1 min 5.58 sec)

六、锁的使用方式分类

1、乐观锁(Optimistic Lock)

乐观锁的特点先进行业务操作,不到万不得已不去拿锁。即“乐观”的认为拿锁多半是会成功的,因此在进行完业务操作需要实际更新数据的最后一步再去拿一下锁就好。
乐观锁是否在事务中其实都是无所谓的,其底层机制是这样:在数据库内部update同一行的时候是不允许并发的,即数据库每次执行一条update语句时会获取被update行的写锁,直到这一行被成功更新后才释放。因此在业务操作进行前获取需要锁的数据的当前版本号,然后实际更新数据时再次对比版本号确认与之前获取的相同,并更新版本号,即可确认这之间没有发生并发的修改。如果更新失败即可认为老版本的数据已经被并发修改掉而不存在了,此时认为获取锁失败,需要回滚整个业务操作并可根据需要重试整个过程。

2、悲观锁(Pessimistic Lock)

悲观锁的特点是先获取锁,再进行业务操作,即“悲观”的认为获取锁是非常有可能失败的,因此要先确保获取锁成功再进行业务操作。通常所说的“一锁二查三更新”即指的是使用悲观锁。通常来讲在数据库上的悲观锁需要数据库本身提供支持,即通过常用的select … for update操作来实现悲观锁。当数据库执行select for update时会获取被select中的数据行的行锁,因此其他并发执行的select for update如果试图选中同一行则会发生排斥(需要等待行锁被释放),因此达到锁的效果。select for update获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。
这里需要注意的一点是不同的数据库对select for update的实现和支持都是有所区别的,例如oracle支持select for update no wait,表示如果拿不到锁立刻报错,而不是等待,mysql就没有no wait这个选项。另外mysql还有个问题是select for update语句执行中所有扫描过的行都会被锁上,这一点很容易造成问题。因此如果在mysql中用悲观锁务必要确定走了索引,而不是全表扫描。

总结


乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能

乐观锁还适用于一些比较特殊的场景,例如在业务操作过程中无法和数据库保持连接等悲观锁无法适用的地方

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/18840.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一分钟教你学浪app视频怎么缓存

你是否在学浪app上苦苦寻找如何缓存视频的方法?你是否想快速、轻松地观看自己喜欢的视频内容?那么,让我们一起探索一分钟教你如何缓存学浪app视频的技巧吧! 学浪下载工具我已经打包好了,有需要的自己下载一下 学浪下…

【JavaScript】ECMAS6(ES6)新特性概览(二):解构赋值、扩展与收集、class类全面解析

🔥 个人主页:空白诗 🔥 热门专栏:【JavaScript】 文章目录 🌿 引言五、 Destructuring Assignment - 解构赋值,数据提取的艺术 🎨📌 数组解构📌 对象解构📌 特…

动态规划之单词拆分

这次分享一道关于动态规划的leetcode,单词拆分。 单词拆分 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。注意:不要求字典中出现的单词全部都使用,并且字典中的单词…

【技术】汉诺塔的递归问题解析及多语言实现

汉诺塔的递归问题解析及多语言实现 汉诺塔(Hanoi Tower)问题是一个非常经典的递归问题。它起源于一个古老的传说:有三个柱子和64个大小不一的金盘,开始时这些金盘按从小到大的顺序放在柱子A上,目标是在柱子B上按同样的…

Java——Java开发环境

一、JDK 1、什么是JDK JDK(Java Development Kit,Java 开发工具包)是用于开发 Java 应用程序的核心工具包。它包含了编写、编译、调试和运行 Java 程序所需的一切工具和库。JDK 是每个 Java 开发者必备的工具。 2、JDK 主要组件 JDK主要包…

HNU-计算机体系结构-实验3-缓存一致性

计算机体系结构 实验3 计科210X 甘晴void 202108010XXX 文章目录 计算机体系结构 实验31 实验目的2 实验过程2.0 预备知识2.0.1 多cache一致性算法——监听法2.0.1.1 MSI协议2.0.1.2 MESI协议2.0.1.3 本题讲解 2.0.2 多cache一致性算法——目录法2.0.2.1 有中心的目录法2.0.2…

A2B V2.0协议学习笔记(非正式版本)

一、说明 A2B全称是 Automotive Audio Bus 汽车音频总线,主要是解决传统音频总线线多、线重、成本贵等问题。 A2B V2.0总线相对V1.0主要变化点: 速率提升,高达98.304Mbps,全双工模式 编码方式,由之前的曼彻斯特编码变为QPSK(正交相移键控)编码,每个符合2bit数据,因此…

随手记:多行文本域存数据有换行,回显数据换行展示

1.在新增的时候存储数据 <el-input type"textarea"v-model"XXXX"></el-input> 2.详情页返回的数据&#xff1a; replace一顿操作确实复杂 最快的方法直接写个样式:style"white-space: pre-line" 即可行内或者class样式都可以 …

B2126 连续出现的字符

连续出现的字符 题目描述 给定一个字符串&#xff0c;在字符串中寻找第一个连续出现次数不低于 k k k 次的字符。 输入格式 2 2 2 行。第 1 1 1 行是 k k k&#xff1b;第 2 2 2 行是仅包含大小写字母的字符串。 输出格式 字符串中第一个连续出现次数不低于 k 次的字符…

Python面试宝典:Python中与动态规划和排序算法相关的面试笔试题(1000加面试笔试题助你轻松捕获大厂Offer)

Python面试宝典:1000加python面试题助你轻松捕获大厂Offer【第二部分:Python高级特性:第十二章:高级数据结构和算法:第二节:Python中实现各类高级数据结构与算法三】 第十二章:高级数据结构和算法第二节:Python中实现各类高级数据结构与算法2.3、python中与动态规划和排…

网页如何给js后台传递数字类型参数

网页无法通过get方法传递数字参数给js后台&#xff0c;就是网页端写的是数字参数&#xff0c;传递给后台也变成了数字字符串。而js对数字类型和字符串类型是不相同的。由于我们的代码是通过中间件挂载接口的&#xff0c;通过joi库检查参数。 const Joi require(joi); //注意&…

秋招突击——算法打卡——5/28——复习{Z字形变换、两数之和}——新做:{整数反转、字符串转整数}

文章目录 复习Z字形变换实现代码参考代码 两数之和复习代码 新作整数反转个人实现实现代码 参考做法字符串转换整数个人解法 分析总结 复习 Z字形变换 实现代码 这里使用了他的思想&#xff0c;但是没有用他的代码&#xff0c;虽然已经比上次简洁了&#xff0c;但是还是不够&…

【日记】终于鼓起勇气买了吹风机!(356 字)

正文 好忙。今天比昨天还要忙&#xff0c;水都没喝几口。嗯&#xff0c;好像只喝了两口。 今天补了一份印鉴卡&#xff0c;销了一个户&#xff0c;变了一个户&#xff0c;弄了一大堆资料找人签字&#xff0c;还顺带要解决一个押品的历史遗留问题。 中午睡得好香&#xff0c;都不…

如何理解和使用 this 关键字

this 关键字是许多编程语言中的一个核心概念&#xff0c;在面向对象编程&#xff08;OOP&#xff09;中尤为重要。在JavaScript、Java、C、C#等语言中&#xff0c;this 扮演着至关重要的角色。理解 this 的意义和用法&#xff0c;对于编写清晰、有效的代码至关重要。 什么是th…

超分论文走读

codeFormer 原始动机 高度不确定性&#xff0c;模糊到高清&#xff0c;存在一对多的映射纹理细节丢失人脸身份信息丢失 模型实现 训练VQGAN 从而得到HQ码本空间作为本文的离散人脸先验。为了降低LQ-HQ映射之间的不确定性&#xff0c;我们设计尽量小的码本空间和尽量短的Code…

ECS搭建2.8版本的redis

要在ECS&#xff08;Elastic Compute Service&#xff09;上手动搭建Redis 2.8版本&#xff0c;你可以按照以下步骤操作&#xff1a; 步骤1&#xff1a;更新系统和安装依赖 首先&#xff0c;登录到你的ECS实例&#xff0c;确保系统是最新的并安装必要的依赖包&#xff1a; s…

运营推广最容易被忽略的细节!用短链接推广必须要掌握这些要点!

短链接是目前很多企业进行网络推广最常用的方式之一&#xff0c;是引流转化的重要桥梁&#xff0c;很多工作者可能觉得用短链接推广&#xff0c;只需要简简单单的把生成好的短链接放上去就行&#xff0c;但是实际上有很多细节要点是需要着重注意的&#xff0c;今天小编就围绕这…

做外贸怎么给新老客户定价

通常情况下我们对于新客户的关注点要比老客户更多一些&#xff0c;大概是因为新客户的开发周期比较长而且不确定性也很大。 但是对于一些返单的老客户对比来讲&#xff0c;老客户的稳定性就会相对来说增加很多&#xff0c;如果款式规格都是固定的&#xff0c;那么老客户从选品…

[AIGC] Nginx常用变量详解

Nginx非常强大&#xff0c;其主要功能包括HTTP服务器、反向代理、负载均衡等。Nginx的配置中有许多内置的变量&#xff0c;你可以在配置文件中使用这些变量进行灵活的配置。在本篇文章中&#xff0c;我们将介绍一些Nginx中常见的变量&#xff0c;包括proxy_add_header。 常见变…

redis显示RDB error

报错问题&#xff1a;"RDB error" 是指在Redis的RDB持久化过程中出现了错误。Redis的RDB持久化是通过将内存中的数据集快照保存到磁盘中的一种方式。如果在这个过程中遇到问题&#xff0c;Redis会记录一条包含"RDB error"的日志信息。上图错误&#xff0c;…