数据库锁及批量更新死锁处理

2023-09-21 20:36:16

数据库锁

  • 间隙锁锁定的是一个间隙范围,而不会锁住某条记录。
  • 共享锁就是读锁,独占锁就是写锁,可以理解为读写锁,读读不互斥,读写互斥,写写互斥,共享锁( S 锁)、独占锁( X 锁)指的就是 InnoDB 上的行锁(记录锁)。
  • 意向锁是InnoDB引擎的一种特殊的表锁,在获取共享锁和独占锁之前必须拿到对应类型的意向锁。
  • 乐观锁悲观锁更多的是体现加锁的思想不同
    • 乐观锁是一种无锁的思想,假设并发冲突总是不会发生,提交时检查数据一致性,如果一致性被破坏则放弃提交,更新时带着 version 就是乐观锁。
    • 悲观锁假设并发冲突一定会发生,每次操作前都会拿锁,通过锁的互斥顺序执行来控制并发,可以认为数据库中的锁都是悲观锁。

锁实现

1.数据库实例锁
  • 对整个数据实例加锁
  • 加锁命令: Flush tables with read lock (FTWRL) 对数据库实例加全局读锁,让整个库处于只读状态,DDL,DML都会被阻塞
  • 解锁命令: unlock tables ,加锁客户端断开的时候也会自动解锁。
  • 使用场景:做全库的逻辑备份;
2.表锁

Mysql Server 层支持

  • 加锁命令:lock tables
  • 解锁命令:unlock tables,加锁客户端断开的时候也会自动解锁。
  • 使用场景:读密集型;写作不频繁的场景;数据量不大的简单应用;全表更新或者删除;

lock tables t1 read 加读锁,会限制本线程只能读 t1 ,其他线程写 t1 会被阻塞
lock tables t2 write 加写锁,会限制本线程只能读写 t2 ,其他线程不能读也不能写 t2,都会被阻塞

3.行锁

InnoDB 引擎支持行锁,共享锁(S)和 独占锁(X),执行更新操作时,会自动加 X 锁,对于普通的查询语句,InnoDB 不会主动加任何锁,可以显示的加锁。

select * from t where ... lock in share mode // 加共享锁 S
select * from t where ... for update         // 加独占锁 X
  • 排它锁(X锁,独占锁)
    • 修改数据语句 update、delete、insert 都会自动给涉及到的数据加上行级排他锁, select 语句默认不会加任何锁,如果查询的时候要加行级排他锁可以使用 select …for update 语句,加行级共享锁可以使用 select … lock in share mode 语句。
    • 事务 1 如果对某张表加了表级排他锁,表示事务 1 可以对该表中的所有记录进行查询和修改,而其它事务只能查询不能修改。并且其它事务不能再往这张表加任何类型的表级锁,也不能给表中的数据行加任何的行级锁。
  • 共享锁(S锁)
    • 数据行对象 A 可以共存多个行级共享锁,这被称为行级共享锁兼容。加了行级共享锁的数据行对象 A 不能再加行级排他锁,所以行级共享锁和行级排他锁是不兼容的。
    • 当事务 1 为某张表添加了表级共享锁,表示事务 1 可以查看表中的所有记录,但不能修改,而且其它事务也只能查看数据不能修改数据。但是其它事务可以再往这张表添加表级共享锁和意向共享锁,其它事务也可以往这张表中的记录添加行级共享锁;但是其它事务不能再往这张表添加表级的排他锁,也不能添加意向排他锁,其它事务也不能往这张表中的记录添加行级排他锁。

更新锁

只有行级更新锁。

  • 当事务 1 给数据行对象 A 加上更新锁后,代表数据行对象 A 将在稍后被更新。更新锁允许其他事务在事务 1 操作更新之前读取数据行对象 A,但不可以修改。其他事务修改数据行对象 A 之前会先往数据行对象 A 加行级排他锁,但是发现数据行对象 A 已存在 U 锁,所以加行级排他锁失败,只能等待 U 锁释放。
  • 更新锁与行级共享锁兼容;更新锁与表级共享锁不兼容;更新锁与更新锁互不兼容;更新锁与行级排他锁不兼容,更新锁与表级排他锁不兼容。
  • 因此数据行对象 A 不可以再添加更新锁,但是可以添加行级共享锁,但是添加行级共享锁的意义不大,因为事务 1 找到需要更新的数据时,更新锁直接转为行级排他锁,开始更新数据,不需要等待其他事务释放行级共享锁,所以在有更新锁的数据资源上加行级共享锁就毫无意义了。

意向锁

InnoDB 的行锁是加载索引上的,如果我们的更新没有走索引导致扫描全表,就会锁全表,锁的是主键索引。

InnoDB 还支持一种特殊的表锁 意向锁,我们先来看一个例子:

事务A:update t set k = 1 where id = 6
事务B:update t set k = 1 
事务A:commit

事务A 会拿 id = 6 这一行的 独占锁,事务B 对整个表进行修改,要对整个表所有行加独占锁,那么需要遍历主键索引树的每个节点,看有没有被别的事务加了共享锁或者独占锁,最终 发现 id = 6 被加了 独占锁,事务B加锁失败,阻塞。这种场景性能很差,如果要对全表加锁,需要遍历索引树检测锁状态。InnoDB 使用意向锁来解决这个问题

  • 乐观锁:认为冲突概率低,操作数据时,不会锁定数据,只有在提交修改时,才检查。如果数据已被修改,则回滚,否则提交。mysql并没有内置乐观锁机制,需要在代码中实现,常见的实现方式是,使用时间戳或者版本号字段,记录每一次对数据的修改。
    • 标志SQL:(1)select id,version from .xxx …;(2)update xxx set … where … and version = 旧version;
    • 使用场景:(1)低冲突环境;(2)读多写少场景;(3)短事务操作;(4)分布式系统;(5)互联网应用;
    • 风险:(1)冲突检测:只有提交时才检测,有冲突会导致所有都回滚;(2)依赖于版本管理;
  • 悲观锁:一种并发控制方法。认为冲突概率高,每次读写前都加锁;
    • 使用方式:参考前面提到的共享锁(S锁)和排他锁(X锁);
    • 使用场景:(1)写操作比较多;(2)并发冲突高;(3)业务需要强一致性的场景;
    • 缺点:(1)性能开销;(2)并发降低;(3)死锁;(4)锁超时;四、意向锁

意向锁是一种不与行锁冲突的表级锁,就是为了解决锁全表场景的锁状态判断的性能问题。意向锁也是InnoDB自动添加的。

常见的意向锁

1.意向共享锁(Intent Share Lock) IS 锁

事务 T1 在给数据行对象添加行级 S 锁前,要先获得 IS 锁。(事务在加共享锁之前 必须拿到表的 意向共享锁)。如果表被加了 IS 锁,说明某个事务对这个表中的某些数据行加了行级 S 锁。当其它事务想要在这个表上加一个表级排他锁时,发现这个表已经加了意向共享锁,那么就不可以加表级的排他锁了。

2.意向排他锁(Intent Exclusive Lock)IX 锁

事务在请求行级 X 锁前,要先获得 IX 锁(事务在加独占锁之前 必须拿到表的 独占共享锁)。
事务 T1 修改 user 表的数据行对象 A,会给数据行对象 A 上一把行级的排他锁,但是在给数据行对象 A 上行级排他锁前会先给 user 表上一把意向排他锁,这时事务 T2 要给 user 表上一个表级的排他锁就会被阻塞。

3.共享意向排他锁(Share Intent Exclusive Lock) SIX 锁

共享意向排他锁的意思是,某事务要读取整个表,并更新其中的某些数据。

意向锁是表级锁和行锁是不互斥的,只有在需要锁全表的行锁的情况下,才会出现互斥的情况,所以意向锁不是传统意义上的表锁,性能比较高。

考虑到意向锁,事务A 会拿 id = 6 的行锁 和 表的意向独占锁,事务A 需要锁全表行锁,直接加锁失败。

4.间隙锁

where条件是一个范围时,数据库会锁定区间数据,主要是解决幻读问题。

使用场景:(1)防止幻读;(2)范围查询;

缺点:(1)性能影响;(2)死锁;(3)复杂性;(4)锁定范围过大,可能导致不必要的锁定冲突;

对索引记录之间的间隙进行加锁,当使用范围查询记录或者更新数据,InnoDB 会给满足条件的的索引记录加锁,而满足查询条件但是不存在的记录集合,称为 间隙 (GAP),InnoDB 也会对这个"间隙"加锁,也叫 GAP Lock,这是为了防止拿锁期间其他的事务插入数据,导致出现幻读现象,读提交级别因为不考虑幻读问题,所以不需要加间隙锁。

间隙锁和被锁的间隙之间是互斥的,间隙锁之间是不存在互斥的。

这里要注意间隙锁 锁的是索引记录项之间的间隙,而并不是索引值之间的间隙,后面 next key-lock 会有演示

5.Next-Key-Lock临键锁

可以理解为一种特殊的间隙锁,临键锁可以解决幻读的问题。

当事务拥有某一行记录的临键锁时,会锁住一段左开右闭的区间。比如后面截图中的3条数据,就生成了4个临键锁,临键锁如下:(1)(-∞,20];(2)(20, 25];(3)(25, 30];(4)(30, +∞];
当更新age=25的记录时,不能增加或者修改age为(25, 30]之间的数

是 InnoDB 加行锁和间隙锁的算法,是一个前开右闭的区间

update t set k = 1 where id = 5

这里会对 id = 5 记录加 Next key-Lock(0,5] 实际就是(0,5)之间的间隙锁和 id = 5 的行锁 组合,当然因为是id是唯一索引,Next key-Lock 会退化成 id = 5 的行锁。

Next key-Lock 加锁规则如下:

(1)、只有访问到的索引记录才会加锁,这里要理解访问到的记录并不一定是查询到的结果

select * from t where id >= 5 and id < 10 for update

Mysql 会通过主键索引查询到 id = 5 的索引记录,注意这里是等值查询,继续往右扫描满足条件的索引记录 ,从这开始就是范围查询了,找到下个记录 id = 10 ,不满足条件退出,那么这里就访问到了 id = 5 ,id = 10 两条记录,都会被加上 Next key-Lock。

(2)、索引上的等值查询,给唯一索引加锁的时候,next-key lock 退化为行锁。

SQL1: update t set k = 1 where id = 5
SQL2: select * from t where id >= 5 and id < 10 for update

SQL1 会加 (0,5] Next key-Lock,因为 id 是主键索引,会退化成 id = 5 的行锁,SQL2 会对 加 (0,5](5,10] 两个Next key-Lock,id = 5 是等值匹配 最终退化成 id = 5 的行锁 和 5,10]

(3)、非唯一索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock 退化为间隙锁。

select * from t where k >=5 and k <= 10 for update

按照加锁规则,会加上 (0,5] ,(5,10] ,(10,15],因为 k = 10 等值查询,最后一条记录是 k = 15,所以退化成 (10,15),最终加的Next key-Lock 是 (0,5] ,(5,10] , (10,15)

4、间隙锁锁的是索引记录项之间的间隙,而并不是索引值之间的间隙

事务A:update set k = 1 where k = 5
事务B:update set k = 0 where k = 10 blocked

分析下这两个事务,如果按照索引的值那我们很容易得到 事务A 的间隙锁为 (0 ,5 )(5 ,10),两边都是开区间,那么事务B 应该不会被阻塞,而实际上事务B会被阻塞,这是因为 间隙锁是加载索引记录项之间的。

我们看索引 k 的结构,事务A 加的间隙锁应该是 ((0,0)(5,5)),((5,5)(15,5)),((15,5)(10,10)) 三个间隙锁,事务B 更新操作相当于插入一条(10,0) 的记录,此时需要在间隙锁中插入记录 ((0,0) (10,0)(5,5)),加锁失败阻塞

**5、**前面说了 Next key-Lock 实际上是InnoDB加锁的算法,是间隙锁和行锁的组合,并不是一个整体,InnoDB申请一个 key 的 Next key-Lock 按照访问记录的顺序去加行锁或者间隙锁。

事务A:select id from t where k = 10 lock in share mode;
事务B:update t set k = 1 where k = 10 ;(blocked)
事务A:insert into t values(8,8)
事务B:DeadLock ERROR

事务A 加 next-key lock ( 5,10 ] 和间隙锁 (10,15 ),具体的顺序是 先加 (5,10 ) 间隙锁、id = 10 的行锁 、 (10,15 )间隙锁 全部加锁成功。
事务B 同样需要加 加 next-key lock ( 5,10 ] 和间隙锁 (10,15 ),具体的顺序是 先加 (5,10 ) 间隙锁 成功,id = 10 的行锁 ,注意此时加锁失败阻塞。
事务A 插入( 8,8) 被事务B (5,10 ) 间隙锁阻塞。此时发生死锁,事务B被回滚。

6、记录锁

mysql的innodb引擎的一种锁定机制,用于锁定和控制单个行记录的访问。

记录锁作用在索引上,对于没有主键和唯一键的表,innodb会自动添加隐藏的聚簇索引,并在该索引上加锁。

批量更新死锁

show processlist

show processlist:主要是查询数据库中哪些线程正在执行,针对比较慢的线程(time的数值比较大的线程)我们可以将其kill掉。此外,show full processlist 返回的结果是实时变化的。

解读:

​ Id:链接mysql 服务器线程的唯一标识,可以通过kill来终止此线程的链接。

User:当前线程链接数据库的用户

Host:显示这个语句是从哪个ip 的哪个端口上发出的。可用来追踪出问题语句的用户

db: 线程链接的数据库,如果没有则为null

Command: 显示当前连接的执行的命令,一般就是休眠或空闲(sleep),查询(query),连接(connect)

Time: 线程处在当前状态的时间,单位是秒

State:显示使用当前连接的sql语句的状态,很重要的列,后续会有所有的状态的描述,请注意,state只是语句执行中的某一个状态,一个 sql语句,已查询为例,可能需要经过copying to tmp table,Sorting result,Sending data等状态才可以完成

Info: 线程执行的sql语句,如果没有语句执行则为null。这个语句可以使客户端发来的执行语句也可以是内部执行的语句

结果处理:

针对执行时间比较长的线程,我们可以直接将其kill掉,直接执行 kill Id号即可。

更多推荐

word的分隔符和分页符

目录1.word中的分隔符和分页有何不同2.word中我想把表格所在的页设置为横向,上下页均为纵向3.表格页末尾的光标回车生成新的页面后,其仍然为横向,而我希望它为纵向1.word中的分隔符和分页有何不同分隔符和分页符在Word中都是用于文本分段的工具,但它们的用途和操作方式有所不同。分隔符是一个广义的概念,包括分页符

MYSQL的锁

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

LVS 负载均衡集群的DR模式配置

集群集群的概述集群技术是一种用于提高系统性能、可用性、容错性和可扩展性的关键方法。它涉及将多个计算资源或节点组合在一起,以协同工作以处理任务、服务请求或数据处理。集群类型无论是哪种集群,都至少包括两台节点服务器,而对外表现成一个整体,只提供一项服务,相当于一台大型计算机。根据群集所针对的目标差异,可分为三种类型的集群负

分布式ETL工具Sqoop实践

Mysql数据准备1、在node02节点登录Mysql。mysql-uroot-proot2、新建数据库testdb。createdatabasetestdb;3、新建数据表ts。usetestdb;createtablets(idint,namevarchar(10),ageint,sexchar(1));4、向表中

hive中的索引

使用索引前的配置在使用Hive索引之前,需要进行一些配置,以确保索引能够正常工作。以下是一些常见的配置步骤:Hive配置在Hive中启用索引功能,需要在Hive配置文件(hive-site.xml)中设置以下属性:<property><name>hive.index.compact.file.uris</name><v

【日记】文章更新计划

有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准https://blog.zysicyj.top文章最后有详细的更新计划{%timeline2023,pink%}第一版发布【完结~开发规范系列】Linux系列重新定位,不再只是简单的说常用命令周二rocketmq更换为nginx系列微服务内容变

好用的一站式MES系统有哪些?全面管理生产流程,实现工厂数字化转型

在现代制造业中,MES制造执行系统已经成为了不可或缺的信息化工具。它为企业建立了规范化、集成化的生产信息管理平台,通过集成管理思想,帮助企业优化流程管控、数字化生产车间,从而显著提升了生产效率。那么,MES系统到底可以为企业解决哪些问题呢?2023年制造工厂生产管理现状信息化现状:许多企业使用ERP系统来管理业务流程,

操作系统权限提升(二十七)之数据库提权-MySQL MOF提权

MySQLMOF提权MOF介绍mof是windows系统的一个“托管对象格式”文件(位置:C:/windows/system32/wbem/mof/),其作用是每隔五秒就会去监控进程创建和死亡,mof目录下有两个文件夹(good与bad)。Windowsserver2003及以下系统每5秒会执行一次mof目录下的文件,

百度SEO不稳定的原因及解决方法(百度SEO不稳定因素的5大包括)

百度SEO优化不稳定介绍:蘑菇号-www.mooogu.cn随着百度SEO算法的不断变化和升级,许多网站的SEO排名经常出现不稳定的情况,这种情况在一定程度上影响了网站的流量和排名,导致网站的质量评分降低。因此,深入分析百度SEO不稳定的原因和解决方法非常必要。百度SEO不稳定因素的5大包括:1.网站内容和质量不佳,没

day06_Java中的流程控制语句

流程控制简单来讲所谓流程就是完成一件事情的多个步骤组合起来就叫做一个流程。在一个程序执行的过程中,各条语句的执行顺序对程序的结果是有直接影响的。我们必须清楚每条语句的执行流程。而且,很多时候要通过控制语句的执行顺序来实现我们想要的功能。流程控制语句分为:顺序结构丶分支结构(if,switch)丶循环结构(for,whi

SpringMvc决战-【SpringMVC之自定义注解】

目录一、前言1.1.什么是注解1.2.注解的用处1.3.注解的原理二.注解父类1.注解包括那些2.JDK基本注解3.JDK元注解4.自定义注解5.如何使用自定义注解(包括:注解标记【没有任何东西】,元数据注解)?三.实例展示1.案例一(获取类与方法上的注解值)1.1导入一个类用于创造实例1.2导入三个注解1.3导入测试

热文推荐