为了解决多个进程访问内存或磁盘中的同一份数据造成的冲突,通常有两种解决方案,一种是多版本;另一种就是锁。MySQL作为一种关系型数据库,其实也是通过这两种方式来解决数据访问冲突的。MySQL数据多版本叫MVCC,同时MySQL使用了各种类型的锁来保证数据一致性。
我们对数据库的操作分为读和写,MySQL在这个层面把锁分成了共享锁(Shared Lock)和独占锁(Exclusive Lock)也称为S锁和X锁。对于相同的数据S锁可以存在多个,但是不能和X锁共存;X锁本身也不可以多个共存。MySQL为了协调表和行数据读写关系还对两个动作设计了锁,那就是“想读”和“想写”;“想读”对应的是意向共享锁(Intention Shared Lock),“想写”对应的是意向独占锁(Intention Exclusive Lock),对于这两个意向锁我们后面再介绍具体用途。
概括来讲:MySQL从用户行为上分了四类锁
读:S锁
写:X锁
想读:IS锁
想写:IX锁 锁的分类:按加锁对象按照加锁对象的不同,分为表锁(对一个表加锁)和行锁(对某行数据加锁)。
MySQL的MyISAM、MEMORY、MERGE三种存储引擎只支持表锁,只有InnoDB支持行锁。接下来我们主要结束下InnoDB中的一些表锁和行锁。
前面按照行为和对象给锁分类,都只是MySQL中锁的一些归类,并不代表具体的锁,MySQL中具体用到的锁我们接下来详细介绍。MySQL有四大存储引擎,MyISAM、MEMORY、MERGE、InnoDB,其中只有InnoDB支持事务和行锁,使用也最为广泛,我们接下来主要介绍InnoDB引擎中的锁。
InnoDB中的表锁:
1.MDL锁
我们在执行DML(SELECT INSERT UPDATE DELETE)语句时,是不会对表加S、X锁的;但是当我们执行DDL语句时,MySQL会加元数据锁(MetadataLock)简称MDL锁。
这个时候大家就需要注意了,如果有事务在对表执行DML操作,就会阻塞我们的DDL操作,同时MDL锁,又会阻塞后面的事务。
在使用“锁定读”或者写操作时,需要给InnoDB中行添加对应的S、X锁,在给行记录添加锁之前,需要对应的先给表添加IS和IX锁。IS和IX锁的作用是在需要添加表级别S、X锁时,判断表内是否有某些行数据存在S、X锁(避免遍历表的所有行)。 这里额外解释一下锁定读:
我们想在读取记录时就为数据加锁的语句称为锁定读,MySQL支持下面两种锁定读的语句:
SELECT...LOCK IN SHARE MODE; 对记录加S锁
SELECT...FOR UPDATE; 对记录加X锁
2.自增主键相关的锁
我们经常会用到自增索引,AUTO_INCREMENT。为了保证插入的主键是连续递增的,当我们执行Insert语句时,“可能会”给表添加表锁,锁的名字叫:AUTO-INC。不过这个表锁在分配完ID后就释放了,不用等到事务提交。这里为什么说“可能会”。因为如果我们Insert语句插入的数据是可以确定条数的,其实可以使用一个单独的锁,为本次插入生成需要的自增主键,然后就立马释放锁。采用轻量级锁还是AUTO-INC也是可以配置的,MySQL有一个系统变量:innodb_autoinc_lock_mode。如果设置为0表示一律使用AUTO-INC锁;如果为1表示插入记录数确定时采用轻量级锁,不确定时采用AUTO-INC锁;如果为2表示一律采用轻量级锁。我们通常会设置为1
InnoDB中的行锁 1.对MySQL中的一条记录加锁,称为记录锁(LOCK_REC_NOT_GAP),记录锁有S、X两种
2. MySQL为了解决在REPEATABLE READ隔离级别下幻读的问题,引入了间隙锁(LOCK_GAP)。举一个例子,假设我们表中有两条记录:
id:5 name:小明
id:8 name:小张
当我们在5和8两条记录中间加GAP锁的时候,两条记录之间是不允许插入数据的。这里有个小问题,中间的记录可以有“间隙”,那第一条记录和最后一条记录怎么办呢?MySQL会给表生成两条伪记录,Infimum和Supermum,前者代表页面中的最小记录,后者代表页的最大记录,gap锁是为了防止插入的数据引起幻读而设计的。
3.如果即要锁住一条记录又要锁住记录的“间隙”,需要Next-key Lock。Next-key Lock本质上就是记录锁+间隙锁
4.插入意向锁,当我们在事务中想要插入一条记录时,需要判断此间隙是否存在gap锁,如果没有的话直接插入就可以了,如果存在gap锁,需要把这个插入数据的意向记录下来,并标记当前处于等待状态,我们把记录插入意向的锁结构称为插入意向锁(LOCK_INSERT_INTENTION)。当gap锁被释放的时候,此区间的插入意向锁们,会同时执行插入操作。
5.延迟加锁:MySQL对INSERT语句采用了延迟加锁的机制。
当执行一条INSERT语句时,(当然,如果插入间隙存在“间隙锁”,需要等到间隙锁的释放,并生成插入意向锁)对于主键索引来说是不加锁的,但是会为当前记录生成一个事务ID(trx_id),当其他事务想要对此语句加S、X锁时,首先看一下当前记录的trx_id是否活跃,如果已经完成则直接加锁,如果还没有完成就为当前记录上的trx_id代表的事务添加一把X锁,同时自己创建一个意向锁。
如果是二级索引,本身没有trx_id,但是二级索引的每一页都有当前页最大的trx_id,如果当前页最大trx_id小于当前最小的活跃trx_id则说明该页所做的修改已经提交,如果不是的话需要通过二级索引找到主键索引,对其做上一步的判断操作。
我们先构造一张curriculum(课程表):其中id是主键 name是二级索引
id | name | teacher |
---|---|---|
1 | 思维 | t1 |
3 | 英语 | t3 |
5 | AI | t5 |
7 | 绘画 | t7 |
我们分别介绍下各种语句的加锁情况,默认是在REPESTABLE READ隔离级别和INNODB引擎下
1.普通查询:select * from curriculum where id = 3;
在REPESTABLE READ隔离级别下,只在第一次查询时,生成读的“数据视图”,来避免脏读、不可重复读和幻读。
但是这里有一种情况下是存在幻读的:
事务一:
事务二:
他们的执行顺序是:
事务一第一步 --> 事务二执行完 -->事务一第二步 --> 事务一第三步。
因为第一步执行完事务一并没对表里的记录加锁,事务二可以成功执行INSERT语句。这个时候事务一执行第二步,此时UPDATE语句需要更新“当前读”的数据,因此会更新事务二插入的id=2的这条记录;然后此时id=2这条记录的最新trx_id变成了事务一的trx_id,所以第三部就查询到了id=2的记录,也就出现了两次查询结果不一致的情况。
2.锁定读、UPDATE、DELETE:这几条语句的加锁方式基本是一样的,我们就只举一个UPDATE的例子
update curriculum set name = "音乐" where id >2 and id <=6;
3.锁定读、UPDATE、DELETE等值条件:
update curriculum set name = "音乐" where id = 2;
id=2的记录不存在,最终会生成区间(1,3)的X型“间隙锁”。
前面讲到的都是唯一索引,如果是二级索引呢?
其实二级索引的加锁判断条件和一级索引相同;同时如果二级索引符合“索引下推”条件,产生回表操作之后,一级索引也会按照同样的规则加锁。
INSERT 语句的锁在前文延迟加锁时已经说过了,就不再重复赘述了。
1.查看获取锁失败或者阻塞的事务:
SELECT * FROM information_schema.INNODB_TRX \G;
然后通过下面这个表可以查询到事务的阻塞先后关系
SELECT * FROM information_schema.INNODB_LOCK_WAITS \G;
注意:不过INNODB_TRX和INNODB_LOCK_WAITS在MySQL8.0的版本已经不再支持了。
2.SHOW ENGINE INNODB STATUS;查看锁的情况及分析死锁信息
SHOW ENGINE INNODB STATUS;返回的信息会比较多,具体如何查看本文就不描述了,大家可以自行搜索相关资料。
3.如何排查MDL锁有没有阻塞我们的SQL
补充:show processlist展示的内容较多可以参照官网的解(https://dev.mysql.com/doc/refman/5.7/en/thread-information.html)
4.执行SELECT * FROM.INNODB_LOCK_WAITS;查看某个表是否被锁定的情况,其中blocking_pid展示的是阻塞的process id,某些情况下可以手动kill掉
1.MySQL事务在真正执行锁定读、UPDATE、DELETE操作前才对相应的索引加行锁,所以尽量把这些语句放在事务的靠后的位置,离commit越近越好,这样锁的时间越短。
2.MySQL在处理INSERT语句时采用的延迟加锁的设计,我们在开发中也可以借鉴。通过一个有序列及对象状态,判断上一次INSERT是否需要加锁,这样可以提高并发。
3.MySQL的间隙锁我们可以学习到,对于不存在的数据我们也可以加锁,在一些业务场景中,可能会有用。
4.大表和小表的DML操作都要谨慎,在业务低峰期进行。
参考资料:
《高性能MySQL》
《MySQL是怎样运行的》
MySQL官网(https://dev.mysql.com/doc/refman/5.7/en/)
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/b5LTjLH2c9RlNSoE5rAdUA
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。