【黄啊码】MySQL入门—13、悲观锁、乐观锁怎么用?什么是行锁、页锁和表锁?死锁了咋办?

news2024/12/23 11:07:21

大家好!我是黄啊码,MySQL的入门篇已经讲到第12个课程了,今天我们继续讲讲大白篇系列——数据库锁

目录

从数据库管理的角度对锁进行划分

共享锁也叫读锁或 S 锁

排它锁也叫独占锁、写锁或 X 锁。

意向锁(Intent Lock)

为什么共享锁会发生死锁的情况?

从程序员的角度对进行划分

乐观锁的版本号机制

乐观锁的时间戳机制

锁的划分有多种方式,这些划分方式都包括哪些?

锁用来对数据进行锁定,我们可以从锁定对象的粒度大小来对锁进行划分,分别为行锁、页锁和表锁。

顾名思义,行锁就是按照行的粒度对数据进行锁定。锁定力度小,发生锁冲突概率低,可以实现的并发度高,但是对于锁的开销比较大,加锁会比较慢,容易出现死锁情况。

页锁就是在页的粒度上进行锁定,锁定的数据资源比行锁要多,因为一个页中可以有多个行记录。当我们使用页锁的时候,会出现数据浪费的现象,但这样的浪费最多也就是一个页上的数据行。页锁的开销介于表锁和行锁之间,会出现死锁。锁定粒度介于表锁和行锁之间,并发度一般。

表锁就是对数据表进行锁定,锁定粒度很大,同时发生锁冲突的概率也会较高,数据访问的并发度低。不过好处在于对锁的使用开销小,加锁会很快。

行锁、页锁和表锁是相对常见的三种锁,除此以外我们还可以在区和数据库的粒度上锁定数据,对应区锁和数据库锁。不同的数据库和存储引擎支持的锁粒度不同,InnoDB 和 Oracle 支持行锁和表锁。而 MyISAM 只支持表锁,MySQL 中的 BDB 存储引擎支持页锁和表锁。SQL Server 可以同时支持行锁、页锁和表锁,如下表所示:


这里需要说明下,每个层级的锁数量是有限制的,因为锁会占用内存空间,锁空间的大小是有限的。当某个层级的锁数量超过了这个层级的阈值时,就会进行锁升级。锁升级就是用更大粒度的锁替代多个更小粒度的锁,比如 InnoDB 中行锁升级为表锁,这样做的好处是占用的锁空间降低了,但同时数据的并发度也下降了。

从数据库管理的角度对锁进行划分

除了按照锁粒度大小对锁进行划分外,我们还可以从数据库管理的角度对锁进行划分。共享锁和排它锁,是我们经常会接触到的两把锁。

共享锁也叫读锁或 S 锁

共享锁锁定的资源可以被其他用户读取,但不能修改。在进行SELECT的时候,会将对象进行共享锁锁定,当数据读取完毕之后,就会释放共享锁,这样就可以保证数据在读取时不被修改。

比如我们想给 product_comment 在表上加共享锁,可以使用下面这行命令:

LOCK TABLE product_comment READ;

当对数据表加上共享锁的时候,该数据表就变成了只读模式,此时我们想要更新 product_comment 表中的数据,比如下面这样:

UPDATE product_comment SET product_id = 10002 WHERE user_id = 912178;

系统会做出如下提示:

ERROR 1099 (HY000): Table 'product_comment' was locked with a READ lock and can't be updated

也就是当共享锁没有释放时,不能对锁住的数据进行修改。

如果我们想要对表上的共享锁进行解锁,可以使用下面这行命令:

UNLOCK TABLE;

如果我们想要给某一行加上共享锁呢,比如想对 user_id=912178 的数据行加上共享锁,可以像下面这样:

SELECT comment_id, product_id, comment_text, user_id FROM product_comment WHERE user_id = 912178 LOCK IN SHARE MODE

排它锁也叫独占锁、写锁或 X 锁。

排它锁锁定的数据只允许进行锁定操作的事务使用,其他事务无法对已锁定的数据进行查询或修改。

如果我们想给 product_comment 数据表添加排它锁,可以使用下面这行命令:

LOCK TABLE product_comment WRITE;

这时只有获得排它锁的事务可以对 product_comment 进行查询或修改,其他事务如果想要在 product_comment 表上查询数据,则需要等待。你可以自己开两个 MySQL 客户端来模拟下。

这时我们释放掉排它锁,使用这行命令即可。

UNLOCK TABLE;

同样的,如果我们想要在某个数据行上添加排它锁,比如针对 user_id=912178 的数据行,则写成如下这样:

SELECT comment_id, product_id, comment_text, user_id FROM product_comment WHERE user_id = 912178 FOR UPDATE;

另外当我们对数据进行更新的时候,也就是INSERTDELETE或者UPDATE的时候,数据库也会自动使用排它锁,防止其他事务对该数据行进行操作。

当我们想要获取某个数据表的排它锁的时候,需要先看下这张数据表有没有上了排它锁。如果这个数据表中的某个数据行被上了行锁,我们就无法获取排它锁。这时需要对数据表中的行逐一排查,检查是否有行锁,如果没有,才可以获取这张数据表的排它锁。这个过程是不是有些麻烦?这里就需要用到意向锁。

意向锁(Intent Lock)

简单来说就是给更大一级别的空间示意里面是否已经上过锁。举个例子,你可以给整个房子设置一个标识,告诉它里面有人,即使你只是获取了房子中某一个房间的锁。这样其他人如果想要获取整个房子的控制权,只需要看这个房子的标识即可,不需要再对房子中的每个房间进行查找。这样是不是很方便?

返回数据表的场景,如果我们给某一行数据加上了排它锁,数据库会自动给更大一级的空间,比如数据页或数据表加上意向锁,告诉其他人这个数据页或数据表已经有人上过排它锁了,这样当其他人想要获取数据表排它锁的时候,只需要了解是否有人已经获取了这个数据表的意向排他锁即可。

如果事务想要获得数据表中某些记录的共享锁,就需要在数据表上添加意向共享锁。同理,事务想要获得数据表中某些记录的排他锁,就需要在数据表上添加意向排他锁。这时,意向锁会告诉其他事务已经有人锁定了表中的某些记录,不能对整个表进行全表扫描。

为什么共享锁会发生死锁的情况?

当我们使用共享锁的时候会出现死锁的风险,下面我们用两个 MySQL 客户端来模拟一下事务查询。

首先客户端 1 开启事务,然后采用读锁的方式对user_id=912178的数据行进行查询,这时事务没有提交的时候,这两行数据行上了读锁。然后我们用客户端 2 开启事务,同样对user_id=912178获取读锁,理论上获取读锁后还可以对数据进行修改,比如执行下面这条语句:

UPDATE product_comment SET product_i = 10002 WHERE user_id = 912178;

当我们执行的时候客户端 2 会一直等待,因为客户端 1 也获取了该数据的读锁,不需要客户端 2 对该数据进行修改。这时客户端 2 会提示等待超时,重新执行事务。

你能看到当有多个事务对同一数据获得读锁的时候,可能会出现死锁的情况。

从程序员的角度对进行划分

如果从程序员的视角来看锁的话,可以将锁分成乐观锁和悲观锁,从名字中也可以看出这两种锁是两种看待数据并发的思维方式。

乐观锁(Optimistic Locking)认为对同一数据的并发操作不会总发生,属于小概率事件,不用每次都对数据上锁,也就是不采用数据库自身的锁机制,而是通过程序来实现。在程序上,我们可以采用版本号机制或者时间戳机制实现。

乐观锁的版本号机制

在表中设计一个版本字段 version,第一次读的时候,会获取 version 字段的取值。然后对数据进行更新或删除操作时,会执行UPDATE ... SET version=version+1 WHERE version=version。此时如果已经有事务对这条数据进行了更改,修改就不会成功。

这种方式类似我们熟悉的 SVN、CVS 版本管理系统,当我们修改了代码进行提交时,首先会检查当前版本号与服务器上的版本号是否一致,如果一致就可以直接提交,如果不一致就需要更新服务器上的最新代码,然后再进行提交。

乐观锁的时间戳机制

时间戳和版本号机制一样,也是在更新提交的时候,将当前数据的时间戳和更新之前取得的时间戳进行比较,如果两者一致则更新成功,否则就是版本冲突。

你能看到乐观锁就是程序员自己控制数据并发操作的权限,基本是通过给数据行增加一个戳(版本号或者时间戳),从而证明当前拿到的数据是否最新。

悲观锁(Pessimistic Locking)也是一种思想,对数据被其他事务的修改持保守态度,会通过数据库自身的锁机制来实现,从而保证数据操作的排它性。

从这两种锁的设计思想中,你能看出乐观锁和悲观锁的适用场景:

  1. 乐观锁适合读操作多的场景,相对来说写的操作比较少。它的优点在于程序实现,不存在死锁问题,不过适用场景也会相对乐观,因为它阻止不了除了程序以外的数据库操作。

  2. 悲观锁适合写操作多的场景,因为写的操作具有排它性。采用悲观锁的方式,可以在数据库层面阻止其他事务对该数据的操作权限,防止读 - 写和写 - 写的冲突。

好了,今天的课程学到这里,有问题的留个言,别忘了一键三连,下次我们还会再见!

我是黄啊码,码字的码,退。。。退。。。退。。。朝! 

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

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

相关文章

C++库——windows下使用Qt5.15.2+mingw64+msys2编译c++数学库GSL

文章目录准备配置msys2编译GSL准备 下载gsl库的源代码。大家可以到GSL的官网下载gsl的源代码。目前版本为2.7,下载完成后解压缩。 下载msys2。msys2是一套在windows上运行的用于构建库和程序的工具库,下载地址可以使用清华源的下载地址。下载完成后&…

【论文解读】伪装物体检测 Camouflaged Object Detection

文章目录伪装物体检测 Camouflaged Object DetectionSINet v1RF模块:PDC模块:SINet v2特征提取Texture Enhanced Module 纹理增强模块Neighbor Connection Decoder 邻居连接解码器Group-Reversal Attention 组反转注意力总结伪装物体检测 Camouflaged Ob…

计算机毕业设计之java+javaweb的烯烃厂压力管道管理平台

项目介绍 系统权限按管理员和用户这两类涉及用户划分。 (a) 管理员;管理员使用本系统涉到的功能主要有:主页、个人中心、通知公告管理、用户管理、管道信息管理、单位信息管理、管道统计信息管理等功能。 (b) 用户登录进入系统可以对主页、个人中心、通…

2022高频经典前端面试题(html+css+js上篇,含答案)

博主经历过多轮面试,因此想将自己的面试经验以及答题技巧,分享给即将面试找前端工作的同学。 2022高频经典前端面试题分为上中下三篇,分别会有html,css,js,es6,vue,ts,nodejs,以及hr面和反问面试官几个维度去进行,完整的还原面试场…

在 Linux 中使用 tcp 转储命令来分析网络

前言 Tcpdump是用于分析网络和查找相关网络问题的出色工具。它会在数据包经过时捕获数据包,并向您显示网络上正在发生的事情和传入情况。该命令的输出显示在 STDOUT 上,也可以存储在文件中。 感谢开发人员,他们将Tcpdump保留为开源项目。它…

LinkedIn最好工具-领英精灵有哪些批量加好友方法?

领英工具-领英精灵有哪些批量加好友方法 使用领英的人都会使用领英精灵,因为领英精灵是目前本土做得最好的领英工具,具有很多强大的功能。特别是拓展人脉方面,提供了很多批量加好友的方法。刚使用的新手可能不知道如何操作,下面就…

施耐德电气“创新开放日”走进中国软件研发中心 以软件与创新驱动产业“双转型”

来源 | 施耐德电气 2022年10月27日,施耐德电气在位于北京亦庄的中国软件研发中心举办“创新开放日”,充分展示其在中国深化研发的战略布局。当天,施耐德电气展示了该中心成立一周年以来的创新研发成果,并与合作伙伴共话软件发展趋…

【jsdoc-to-markdown】一步步实现js文件的文档生成

文章目录导读开发环境安装Vs code插件:Doxygen Documentation Generator效果优势jsdoc-to-markdown的使用了解 jsdocjsdoc-to-markdown安装创建测试文件example.jsjsdoc-to-markdown使用jsdoc-to-markdown踩坑!!!参考资料导读 这个…

【C++】一文带你吃透string的模拟实现 (万字详解)

🌈欢迎来到C专栏~~ 模拟实现string (꒪ꇴ꒪(꒪ꇴ꒪ )🐣,我是Scort🎓🌍博客主页:张小姐的猫~江湖背景快上车🚘,握好方向盘跟我有一起打天下嘞!送给自己的一句鸡汤🤔&#…

生态流量智能终端机 水电站生态流量多媒体智能终端-视频叠加、数据采集、远程传输

平升电子生态流量智能终端机 水电站生态流量多媒体智能终端是一款集人机交互、视频叠加、4G路由、数据采集、逻辑运算与远程传输功能于一体的多媒体智能终端设备。 此款产品为水电站生态流量监测项目的专用产品,便于监管单位及时掌握水电站的流量下泄情况&#xff…

【Django框架】——19 Django视图 01 路由配置

文章目录一、视图介绍二、路由配置1. 配置URLconf2.编辑项目中urls.py(根路由)3.创建应用中 urls.py (子路路由)4.路由文件urls.py5.API讲解一、视图介绍 视图就是应⽤用中views.py⽂文件中的函数 视图的第⼀个参数必须为HttpRequest对象,还…

计算多张图片的移位距离

( A, B )---25*30*2---( 1, 0 )( 0, 1 ) 做一个二分类的网络分类A和B,让A和B的训练集中都有多张图片,用一种平均值的办法把多张图片等效成两张图片,统计两张图片的移位距离,并比较移位距离和迭代次数的关系。 设AB训练集都只有两…

Python编程 赋值,逻辑,位运算符

作者简介:一名在校计算机学生、每天分享Python的学习经验、和学习笔记。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 目录 前言 一.赋值运算符 1.基本赋值运算符 2.注意 二.逻辑运算符 1.逻辑运算符使…

【LeetCode】No.70. Climbing Stairs -- Java Version

题目链接:https://leetcode.com/problems/climbing-stairs/ 1. 题目介绍(Climbing Stairs) You are climbing a staircase. It takes n steps to reach the top. 【Translate】: 你正在爬楼梯,爬到山顶要走n步。 Each…

最受欢迎的职业榜单!医生还是程序员?

最受欢迎的男友职业排行榜终于更新了,医生荣归榜首成为了第一名。 出人意外的是,公务员竟然只排名第六。 榜单上可以看出程序员也霸榜,占据了排行前三的位置。 程序员相对于医生有什么样的优势呢? 首先是逻辑分析能力。 虽然医生…

CMSC5707-高级人工智能之自编码器Auto-encoders

这章讲述模型框架和概念的时间较多,好像并没有涉及过多的运算,重在一些概念的理解。 Traditional Autoencoder 传统的自编码器常用来进行图像去噪的任务,需要了解其模型架构和流程。 自编码器由两部分组成:从Noisy Input到Z称为…

【附源码】计算机毕业设计java学生社团管理系统设计与实现

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

Python Flask教程学习02

书接上文Python Flask教程学习01 文章目录Flask 教程Flask 会话Flask 消息闪现Flask 文件上传Flask 扩展/寻找扩展Flask 教程 Flask 会话 与Cookie不同,Session(会话)数据存储在服务器上。会话是客户端登录到服务器并注销服务器的时间间隔。…

jmap:java内存映像工具【详细】

目录jmap概述:jmap 命令格式jmap -heap mid-histo[:live] midjmap -finalizerinfo midjamp -dump:[live,] formatb,filejmap概述: jmap命令用于生成堆转储快照j。jmap的作用不仅仅是为了获取dump文件,它还可以查询finalize执行对垒、java堆和…

【转】推送消息推送机制

原文链接:推送消息&推送机制 - 知乎 消息推送(push)用一句话解释就是:服务端向客户端发送了一条消息,我们在通知栏、锁屏通知、微信消息等等之类的都是消息推送。 1/推送类型有哪些? 消息推送根据业…