MySQL中innodb的行锁算法
众所周知,innodb是默认行锁,当然也支持表锁。如下是对于行锁的算法进行的一些实验。
10余年的沙坡头网站建设经验,针对设计、前端、开发、售后、文案、推广等六对一服务,响应快,48小时及时工作处理。全网整合营销推广的优势是能够根据用户设备显示端的尺寸不同,自动调整沙坡头建站的显示方式,使网站能够适用不同显示终端,在浏览器中调整网站的宽度,无论在任何一种浏览器上浏览网站,都能展现优雅布局与设计,从而大程度地提升浏览体验。创新互联公司从事“沙坡头网站设计”,“沙坡头网站推广”以来,每个客户项目都认真落实执行。
锁的算法为:我知道是行锁,但是是如何锁的,锁多少数据
假如有个索引是:[1,2,3,7]
record lock 锁的是 1,2,3,7
gap lock 锁的是 (- ,1),(2,3),(3,7),(7,+ )反正锁的就是区间,不是行
next-key lock锁的是 (- ,1],[2,3),[3,7),[ 7,+ )既锁范围也锁行
Innodb锁算法规则如下:
在可重复读隔离级别下,innodb默认使用的是next-key lock算法,当查询的索引是主键或者唯一索引的情况下,才会退化为record lock,在使用next-key lock算法时,不仅仅会锁住范围,还会给范围最后的一个键值加一个gap lock。
其中lockmode中的X锁为左边会话中的锁,因为需要显式的commit之后才会释放锁,第二个S锁,为右边的共享锁,因为主键ID为1的已经被锁住了,所以处于锁等待状态,锁的类型为record lock
使用辅助索引a=8进行操作,这个时候理论应该对主键索引加record lock 则 主键ID=8的被锁,然后辅助索引被加next-key lock 则为:
(7,8] 然后对下一个键值加gap锁,则为:(8,11)
所以目前被锁住的记录为:
1.主键为8的被锁
2.辅助索引8的被锁
3.辅助索引8到11之间的被锁,意味着你这个时候往8到11之间写数据会报错
当使用范围条件进行更新时,此时肯定是需要加X锁的,我是用的也是主键,所以按照理论应该是加的record lock ,但是却加了gap lock,因为插入值为10的阻塞了,查看information 也提示X.GAP
这个有点晕为啥主键变成了next-key lock ,不应该是record lock么?
update20200515
在知乎看到的一个解释:
即,在无论使用主键索引还是非主键索引的时候,请求共享锁或者排他锁,innodb会给范围内的记录加锁,而范围内的间隙也会被加锁,
例如一个表t 的 id为1,2,3,7,10
假如执行如下:
select * from t where id =3 for update
那么这个时候执行
insert into t(id) values(8) 会被阻塞,因为是在请求排他锁时使用了范围,所以[3,10],甚至10以后的任何数据都无法插入。
执行
select * from t where id =3 lock in share mode
insert into t(id) values(8) 会被阻塞,因为是在请求共享锁时使用了范围,所以[3,10],甚至10以后的任何数据都无法插入。
幻读是同一事务下,连续执行两次同样的sql可能导致不同的结果,第二次返回的数据可能导致以前不存在的行。
同时一般会问它和脏读的区别,脏读为读取到其他事务未提交的数据,但是幻读是读取的其他事务已经提交的数据。
reference:
MySQL数据库表被锁、解锁,删除事务
在程序员的职业生涯中,总会遇到数据库表被锁的情况,前些天就又撞见一次。由于业务突发需求,各个部门都在批量操作、导出数据,而数据库又未做读写分离,结果就是:数据库的某张表被锁了!
用户反馈系统部分功能无法使用,紧急排查,定位是数据库表被锁,然后进行紧急处理。这篇文章给大家讲讲遇到类似紧急状况的排查及解决过程,建议点赞收藏,以备不时之需。
用户反馈某功能页面报502错误,于是第一时间看服务是否正常,数据库是否正常。在控制台看到数据库CPU飙升,堆积大量未提交事务,部分事务已经阻塞了很长时间,基本定位是数据库层出现问题了。
查看阻塞事务列表,发现其中有锁表现象,本想利用控制台直接结束掉阻塞的事务,但控制台账号权限有限,于是通过客户端登录对应账号将锁表事务kill掉,才避免了情况恶化。
下面就聊聊,如果当突然面对类似的情况,我们该如何紧急响应?
想象一个场景,当然也是软件工程师职业生涯中会遇到的一种场景:原本运行正常的程序,某一天突然数据库的表被锁了,业务无法正常运转,那么我们该如何快速定位是哪个事务锁了表,如何结束对应的事物?
首先最简单粗暴的方式就是:重启MySQL。对的,网管解决问题的神器——“重启”。至于后果如何,你能不能跑了,要你自己三思而后行了!
重启是可以解决表被锁的问题的,但针对线上业务很显然不太具有可行性。
下面来看看不用跑路的解决方案:
遇到数据库阻塞问题,首先要查询一下表是否在使用。
如果查询结果为空,那么说明表没在使用,说明不是锁表的问题。
如果查询结果不为空,比如出现如下结果:
则说明表(test)正在被使用,此时需要进一步排查。
查看数据库当前的进程,看看是否有慢SQL或被阻塞的线程。
执行命令:
该命令只显示当前用户正在运行的线程,当然,如果是root用户是能看到所有的。
在上述实践中,阿里云控制台之所以能够查看到所有的线程,猜测应该使用的就是root用户,而笔者去kill的时候,无法kill掉,是因为登录的用户非root的数据库账号,无法操作另外一个用户的线程。
如果情况紧急,此步骤可以跳过,主要用来查看核对:
如果情况紧急,此步骤可以跳过,主要用来查看核对:
看事务表INNODB_TRX中是否有正在锁定的事务线程,看看ID是否在show processlist的sleep线程中。如果在,说明这个sleep的线程事务一直没有commit或者rollback,而是卡住了,需要手动kill掉。
搜索的结果中,如果在事务表发现了很多任务,最好都kill掉。
执行kill命令:
对应的线程都执行完kill命令之后,后续事务便可正常处理。
针对紧急情况,通常也会直接操作第一、第二、第六步。
这里再补充一些MySQL锁相关的知识点:数据库锁设计的初衷是处理并发问题,作为多用户共享的资源,当出现并发访问的时候,数据库需要合理地控制资源的访问规则,而锁就是用来实现这些访问规则的重要数据结构。
根据加锁的范围,MySQL里面的锁大致可以分成全局锁、表级锁和行锁三类。MySQL中表级别的锁有两种:一种是表锁,一种是元数据锁(metadata lock,MDL)。
表锁是在Server层实现的,ALTER TABLE之类的语句会使用表锁,忽略存储引擎的锁机制。表锁通过lock tables… read/write来实现,而对于InnoDB来说,一般会采用行级锁。毕竟锁住整张表影响范围太大了。
另外一个表级锁是MDL(metadata lock),用于并发情况下维护数据的一致性,保证读写的正确性,不需要显式的使用,在访问一张表时会被自动加上。
常见的一种锁表场景就是有事务操作处于:Waiting for table metadata lock状态。
MySQL在进行alter table等DDL操作时,有时会出现Waiting for table metadata lock的等待场景。
一旦alter table TableA的操作停滞在Waiting for table metadata lock状态,后续对该表的任何操作(包括读)都无法进行,因为它们也会在Opening tables的阶段进入到Waiting for table metadata lock的锁等待队列。如果核心表出现了锁等待队列,就会造成灾难性的后果。
通过show processlist可以看到表上有正在进行的操作(包括读),此时alter table语句无法获取到metadata 独占锁,会进行等待。
通过show processlist看不到表上有任何操作,但实际上存在有未提交的事务,可以在information_schema.innodb_trx中查看到。在事务没有完成之前,表上的锁不会释放,alter table同样获取不到metadata的独占锁。
处理方法:通过 select * from information_schema.innodb_trxG, 找到未提交事物的sid,然后kill掉,让其回滚。
通过show processlist看不到表上有任何操作,在information_schema.innodb_trx中也没有任何进行中的事务。很可能是因为在一个显式的事务中,对表进行了一个失败的操作(比如查询了一个不存在的字段),这时事务没有开始,但是失败语句获取到的锁依然有效,没有释放。从performance_schema.events_statements_current表中可以查到失败的语句。
处理方法:通过performance_schema.events_statements_current找到其sid,kill 掉该session,也可以kill掉DDL所在的session。
总之,alter table的语句是很危险的(核心是未提交事务或者长事务导致的),在操作之前要确认对要操作的表没有任何进行中的操作、没有未提交事务、也没有显式事务中的报错语句。
如果有alter table的维护任务,在无人监管的时候运行,最好通过lock_wait_timeout设置好超时时间,避免长时间的metedata锁等待。
关于MySQL的锁表其实还有很多其他场景,我们在实践的过程中尽量避免锁表情况的发生,当然这需要一定经验的支撑。但更重要的是,如果发现锁表我们要能够快速的响应,快速的解决问题,避免影响正常业务,避免情况进一步恶化。所以,本文中的解决思路大家一定要收藏或记忆一下,做到有备无患,避免突然状况下抓瞎。
mysql表被锁了怎么解锁
重启mysql服务
执行show processlist,找到state,State状态为Locked即被其他查询锁住。KILL 10866。
mysql存储过程出现锁表锁行的情况怎么解决
行锁的等待
在介绍如何解决行锁等待问题前,先简单介绍下这类问题产生的原因。产生原因简述:当多个事务同时去操作(增删改)某一行数据的时候,MySQL 为了维护 ACID 特性,就会用锁的形式来防止多个事务同时操作某一行数据,避免数据不一致。只有分配到行锁的事务才有权力操作该数据行,直到该事务结束,才释放行锁,而其他没有分配到行锁的事务就会产生行锁等待。如果等待时间超过了配置值(也就是 innodb_lock_wait_timeout 参数的值,个人习惯配置成 5s,MySQL 官方默认为 50s),则会抛出行锁等待超时错误。
如上图所示,事务 A 与事务 B 同时会去 Insert 一条主键值为 1 的数据,由于事务 A 首先获取了主键值为 1 的行锁,导致事务 B 因无法获取行锁而产生等待,等到事务 A 提交后,事务 B 才获取该行锁,完成提交。这里强调的是行锁的概念,虽然事务 B 重复插入了主键,但是在获取行锁之前,事务一直是处于行锁等待的状态,只有获取行锁后,才会报主键冲突的错误。当然这种 Insert 行锁冲突的问题比较少见,只有在大量并发插入场景下才会出现,项目上真正常见的是 updatedelete 之间行锁等待,这里只是用于示例,原理都是相同的。
三、产生的原因根据我之前接触到的此类问题,大致可以分为以下几种原因
MySQL从入门到精通(九) MySQL锁,各种锁
锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,除传统的计算资源(CPU、RAM、I/O)争用外,数据也是一种供许多用户共享的资源,如何保证数据并发访问的一致性,有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素,从这个角度来说,锁对数据库而言是尤其重要,也更加复杂。MySQL中的锁,按照锁的粒度分为:1、全局锁,就锁定数据库中的所有表。2、表级锁,每次操作锁住整张表。3、行级锁,每次操作锁住对应的行数据。
全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML的写语句,DDL语句,已经更新操作的事务提交语句都将阻塞。其典型的使用场景就是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性。但是对数据库加全局锁是有弊端的,如在主库上备份,那么在备份期间都不能执行更新,业务会受影响,第二如果是在从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志,会导致主从延迟。
解决办法是在innodb引擎中,备份时加上--single-transaction参数来完成不加锁的一致性数据备份。
添加全局锁: flush tables with read lock; 解锁 unlock tables。
表级锁,每次操作会锁住整张表.锁定粒度大,发送锁冲突的概率最高,并发读最低,应用在myisam、innodb、BOB等存储引擎中。表级锁分为: 表锁、元数据锁(meta data lock, MDL)和意向锁。
表锁又分为: 表共享读锁 read lock、表独占写锁write lock
语法: 1、加锁 lock tables 表名 ... read/write
2、释放锁 unlock tables 或者关闭客户端连接
注意: 读锁不会阻塞其它客户端的读,但是会阻塞其它客户端的写,写锁既会阻塞其它客户端的读,又会阻塞其它客户端的写。大家可以拿一张表来测试看看。
元数据锁,在加锁过程中是系统自动控制的,无需显示使用,在访问一张表的时候会自动加上,MDL锁主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作。为了避免DML和DDL冲突,保证读写的正确性。
在MySQL5.5中引入了MDL,当对一张表进行增删改查的时候,加MDL读锁(共享);当对表结构进行变更操作时,加MDL写锁(排他).
查看元数据锁:
select object_type,object_schema,object_name,lock_type,lock_duration from performance_schema_metadata_locks;
意向锁,为了避免DML在执行时,加的行锁与表锁的冲突,在innodb中引入了意向锁,使得表锁不用检查每行数据是否加锁,使用意向锁来减少表锁的检查。意向锁分为,意向共享锁is由语句select ... lock in share mode添加。意向排他锁ix,由insert,update,delete,select。。。for update 添加。
select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_lock;
行级锁,每次操作锁住对应的行数据,锁定粒度最小,发生锁冲突的概率最高,并发读最高,应用在innodb存储引擎中。
innodb的数据是基于索引组织的,行锁是通过对索引上的索引项加锁来实现的,而不是对记录加的锁,对于行级锁,主要分为以下三类:
1、行锁或者叫record lock记录锁,锁定单个行记录的锁,防止其他事物对次行进行update和delete操作,在RC,RR隔离级别下都支持。
2、间隙锁Gap lock,锁定索引记录间隙(不含该记录),确保索引记录间隙不变,防止其他事物在这个间隙进行insert操作,产生幻读,在RR隔离级别下都支持。
3、临键锁Next-key-lock,行锁和间隙锁组合,同时锁住数据,并锁住数据前面的间隙Gap,在RR隔离级别下支持。
innodb实现了以下两种类型的行锁
1、共享锁 S: 允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
2、排他锁 X: 允许获取排他锁的事务更新数据,阻止其他事务获得相同数据集的共享锁和排他锁。
insert 语句 排他锁 自动添加的
update语句 排他锁 自动添加
delete 语句 排他锁 自动添加
select 正常查询语句 不加锁 。。。
select 。。。lock in share mode 共享锁 需要手动在select 之后加lock in share mode
select 。。。for update 排他锁 需要手动在select之后添加for update
默认情况下,innodb在repeatable read事务隔离级别运行,innodb使用next-key锁进行搜索和索引扫描,以防止幻读。
间隙锁唯一目的是防止其它事务插入间隙,间隙锁可以共存,一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用的间隙锁。
标题名称:mysql行锁怎么释放,mysql行锁的作用
URL标题:http://scgulin.cn/article/hsgsjj.html