mysql行锁

wgchen~ wgchen~     2022-12-28     383

关键词:

场景

行锁是针对数据表中行记录的锁,MySQL行锁是引擎层实现的,不是所有的引擎都支持行锁,MyISAM 引擎就不支持行锁。不支持行锁意味着并发控制只能使用表锁,InnoDB是支持行锁的,这也是MyISAM 被 InnoDB 替代的重要原因之一。

两阶段锁


以上面表格中的例子,在事务 A 执行没有进行commit之前,事务B的update 语句会进行阻塞,直到事务A执行commit之后,事务B才能进行提交。也就是说,在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是做完操作就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。

两阶段锁,锁的添加与释放分到两个阶段进行,之间不允许交叉加锁和释放锁。也就是在事务开始执行后为涉及到的行按照需要加锁,但执行完不会立刻释放,而是事务结束后统一释放。

思考

这对使用事务有什么帮助呢?

如果事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。如果把并发度影响较高的语句放在前面的话,可能会造成事务之间锁等待的时间较长,从而影响并发度。所以要放在操作的最后,这样最大程度减少事务之间的锁等待,提升并发度。

死锁和死锁检测

死锁是 当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待线程释放资源时,就会导致这几个线程进入无限循环等待的状态。

这时候,事务A在等待事务B释放id = 2 的行锁,而事务B在等待事务A释放id = 1 的行锁。事务A和事务B都在等待对方释放锁,就进入了死锁。

出现死锁后,有两种策略:

第一种:进入等待,直至超时。这个超时时间可以通过参数 innodb_lock_wait_timeout 进行设置。

第二种:

发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数innodb_deadlock_detect 设置为 on,表示开启这个逻辑。

如果使用第一种策略,进入等待,默认的超时时间为50秒,意味着出现思索后,第一个被锁的线程要等待50秒之后才能超时退出,其他业务才能继续执行,这个等待时间,大大会影响性能,在生产环境是绝对不允许的。

那可不可以将这个时间设置为很小的值呢?

比如1秒。这样当出现死锁的时候,确实很快就可以解开,但如果不是死锁,而是简单的锁等待呢?所以,超时时间设置太短的话,会出现很多误伤。

所以第一种策略有点不大妥当,正常情况下还是采用第二种策略,进行死锁检测。如果有死锁发生,是能快速发现并且进行处理的,但是它也有额外的负担。

可以想象一下,每个事务被锁的时候,都要进行查看所依赖的线程有没有被别的线程锁住,如此循环,最后判断是否出现了死锁。

思考

按照上面的策略操作了,为什么有时候我服务器CPU消耗近100%,但是数据库却没有执行几个事务啊?

假设有1000个并发线程要同时更新同一行,那么死锁检测就是100量级的。为什么是100万量级呢?因为每一个都需要检测其他999个线程,整体消耗是O(N2)级别的。试想一下,单个线程加锁时的死锁检测时间是O(N),N个并发的死锁检测就是O(N2)。

并发更新同一行的1000个线程,整体耗费的死锁检测操作为1000*1000=100万。

为什么是个乘法——并发更新此行R1的某单个线程Tx,其所作的死锁检测工作为,Tx会有查看锁持有情况,耗费1000此操作——a.查看自身持有的行锁; b.遍历其他999个线程所持有的行锁,总共为1+999=1000次。

为什么会遍历其他999个线程,而不是仅看当前持有R1行锁的这个线程就行了?—— 因为行锁排队。

某线程Tm排队获取R1行锁,排在Tx前。如果Tx当前持有行锁R2,过会Tm先于Tx获持R1后,会变成——Tm持有R1,等待R2 && Tx持有R2,等待R1——Tm和Tx成环死锁。因此并发更新同一行的有N个线程,对应的死锁检测耗费代价为O(N2) ! 死锁检测不可避免,为防止死锁检测代价过高引起性能问题——想办法减少同时对同一行的更新的并发并发度。即降低N值。

热点数据性能问题

那我们该如何处理热点数据更新导致的性能问题呢?

要知道症状是什么?

死锁检测需要消耗大量的CPU资源。

1、如果能确保业务一定不会出现死锁,可以临时将死锁检测关闭。但是会带来一定的风险,因为业务设计的时候死锁并不是一个严重的错误,出现死锁了就进行回滚,通过业务重试一般就没问题了,对业务是无损的。关掉死锁检测可能导致大量超时,这是业务有损的

2、控制并发度,比如同一行同时最多只有 10 个线程在更新,那么死锁检测的成本很低,就不会出现这个问题。控制并发量不但可以减少死锁的概率,也可以减少死锁检测带来的性能消耗。

小结问题汇总

1、两阶段锁的概念是什么? 对事务使用有什么帮助?

2、死锁的概念是什么? 举例说明出现死锁的情况。

3、死锁的处理策略有哪几种?

4、等待超时处理死锁的机制什么?有什么局限?

5、死锁检测处理死锁的机制是什么? 有什么局限?

6、有哪些思路可以解决热点更新导致的并发问题?

面试题2:mysql的行锁

mysql的锁是由具体的存储引擎实现的。InnoDB支持行锁和事务Mysql有三种级别的锁定:表级锁定、页级锁定、行级锁定  查看详情

day871.行锁-mysql实战(代码片段)

行锁Hi,我是阿昌,今天学习记录的是关于行锁的内容。MySQL的行锁是在引擎层由各个引擎自己实现的。但并不是所有的引擎都支持行锁,比如MyISAM引擎就不支持行锁。不支持行锁意味着并发控制只能使用表锁,对... 查看详情

Mysql 表锁代替行锁

】Mysql表锁代替行锁【英文标题】:Mysqltablelockinsteadofrowlocks【发布时间】:2013-12-0205:23:35【问题描述】:Mysql(5.5)Innodb在这种情况下是放置表锁而不是行锁。这会导致对表的其他插入查询失败。这也是更大交易的一部分。Insertintot... 查看详情

从头开始搞懂mysql(05)行锁表锁全局锁(代码片段)

1、行锁行锁是针对数据表中行记录的锁,MySQL的行锁是在引擎层实现的,并不是所有的引擎都支持行锁,比如MyISAM就不支持,InnoDB支持行锁,避免了并发控制时使用表锁1.1两阶段锁在InnoDB事务中,行锁是在... 查看详情

mysql的行锁

...45讲》这本书,当时看完了MySQL的全局锁、表级锁还有行锁和间隙锁。其中的行锁和间隙锁迟迟无法理解,最近趁着有空再次阅读了一遍,并且对照了《深入浅出MySQL》,发现对MySQL锁的理解又上了一个台阶,今... 查看详情

mysql行锁+可重复读+读提交

行锁innodb支持行锁,myisam只支持表锁,同一时刻每张表只能有一条数据被更新在InnoDB事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。如果你的事务... 查看详情

请教一下mysql行锁命令是啥?

请教一下mysql行锁命令是什么?有具体例子吗?MySQL5.1支持对MyISAM和MEMORY表进行表级锁定,对BDB表进行页级锁定,对InnoDB表进行行级锁定。如果不能同时插入,为了在一个表中进行多次INSERT和SELECT操作,可以在临时表中插入行并且立... 查看详情

mysql行锁深入研究(代码片段)

...于业务逻辑的需要,必须对数据表的一行或多行加入行锁,举个最简单的例子,图书借阅系统。假设id=1的这本书库存为1,但是有2个人 查看详情

mysql----共享锁独占锁行锁表锁(代码片段)

...s)2、锁定读(LockingReads)2.1共享锁2.2独占锁2.2锁定读语句3、行锁3.1行锁3.1.1RecordLocks(记录锁)3.1.2GapLocks3.1.3Next-KeyLock3.1.4InsertIntentionLocks3.1.5隐式锁3.2表锁3.2.1表锁的S、X锁3.2.2表锁意向锁的IS、IX锁3.2.3表级别的AU 查看详情

mysql悲观锁是行锁还是表锁?(代码片段)

mysql悲观锁是行锁还是表锁?结论悲观锁在非主键、非索引时是表锁,在主键、索引时是行锁。使用悲观锁在查询语句后面加上forupdate开启悲观锁。select*fromtablewherecol=xxforupdate;悲观锁:在事务执行开始加锁,此... 查看详情

mysql悲观锁是行锁还是表锁?(代码片段)

mysql悲观锁是行锁还是表锁?结论悲观锁在非主键、非索引时是表锁,在主键、索引时是行锁。使用悲观锁在查询语句后面加上forupdate开启悲观锁。select*fromtablewherecol=xxforupdate;悲观锁:在事务执行开始加锁,此... 查看详情

mysql中innodb引擎的行锁是通过加在啥上完成

参考技术A行锁的等待在介绍如何解决行锁等待问题前,先简单介绍下这类问题产生的原因。产生原因简述:当多个事务同时去操作(增删改)某一行数据的时候,MySQL为了维护ACID特性,就会用锁的形式来防止多个事务同时操作... 查看详情

mysql数据库表锁行锁

mysql有2种常见的锁:表锁和行锁一、表锁1)读锁假如当前有2个session,session1获得表table的读锁,对表table进行查询,并尚未释放读锁,因为读锁是读共享锁,所以此时session2也是可以对table进行读操作。... 查看详情

mysql-锁

InnoDB行锁实现方式InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,... 查看详情

mysql基础篇之行锁--07(代码片段)

Mysql基础篇之行锁--06前言从两阶段锁说起死锁和死锁检测小结前言在上一篇文章中,我跟你介绍了MySQL的全局锁和表级锁,今天我们就来讲讲MySQL的行锁。MySQL的行锁是在引擎层由各个引擎自己实现的。但并不是所有的引... 查看详情

mysql中的行锁(代码片段)

1、行锁分类1、记录锁:即锁住记录本身2、间隙锁:锁住一段没有记录的间隙,可以是两条记录的中间部分,也可以是第一条记录的前置部分或最后一条记录的后续部分2.1需要注意的是,间隙锁仅仅是阻塞对... 查看详情

mysql锁--02---行锁(记录锁(recordlocks))(代码片段)

...,如何生成可参考右边的帮助文档文章目录前置知识行锁特点InnoDB与MyISAM的最大不同有两点:==行锁支持事务==ACID并发事务带来的问题事务隔离级别常看当前数据库的事务隔离级别:showvariableslike'tx_isola... 查看详情

关于mysql中的表锁和行锁

什么情况下会触发表锁和行锁mysql行锁和表锁锁是计算机协调多个进程或纯线程并发访问某一资源的机制。在数据库中,除传统的计算资源(CPU、RAM、I/O)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访... 查看详情