mysql锁了怎么解决 mysql的锁( 三 )


下面就聊聊 , 如果当突然面对类似的情况 , 我们该如何紧急响应?
想象一个场景,当然也是软件工程师职业生涯中会遇到的一种场景:原本运行正常的程序,某一天突然数据库的表被锁了,业务无法正常运转,那么我们该如何快速定位是哪个事务锁了表,如何结束对应的事物?
首先最简单粗暴的方式就是:重启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的独占锁 。

推荐阅读