本文转载自微信公众号《大数据DT》,作者小鱼冰河。转载本文请联系大数据DT公众号。1死锁的产生和死锁的防止有四个必要条件,即互斥条件、非抢占条件、请求保持条件和循环等待条件,如图1-6所示。▲图1-6死锁的必要条件1.互斥条件在一段时间内,计算机中的某一资源只能被一个进程占用。此时,如果其他进程请求该资源,则只能等待。2.不可剥夺条件一个进程获得的资源在用完之前不能被其他进程强行夺走,只能由获得资源的进程主动释放。3.请求并持有条件进程至少获得了一个资源并请求其他资源,但是所请求的资源已经被其他进程占用。这时候请求进程就会被阻塞,不会释放已经获得的资源。4.循环等待条件系统中的进程相互等待,同时各自占用的资源会被下一个进程请求。比如有3个进程,进程A,进程B,进程C,进程A申请的资源被进程B占用,进程B申请的资源被进程C占用,进程C申请的资源为被进程A占用,从而形成循环等待状态,如图1-7所示。▲图1-7死锁的循环等待条件需要注意的是,只有当四个必要条件都满足时,才会发生死锁。处理死锁的方法有四种,分别是死锁预防、死锁避免、死锁检测和死锁解决,如图1-8所示。▲图1-8处理死锁的方法预防死锁:处理死锁最直接的方法就是破坏死锁的四个必要条件中的一个或多个,以防止死锁的发生。避免死锁:在分配系统资源的过程中,使用某种策略或方法来防止系统进入不安全状态,从而避免死锁的发生。检测死锁:这种方法允许系统在运行过程中出现死锁,但它可以检测到死锁的发生,并采取适当的措施来清除死锁。死锁消除:当检测到死锁时,使用适当的策略和方法将进程从死锁状态中释放出来。在实际工作中,通常采用有序资源分配法和银行家算法来避免死锁。你可以自己去理解。2MySQL中的死锁问题在MySQL5.5.5及以上版本中,MySQL默认的存储引擎是InnoDB。存储引擎使用行级锁,在某些情况下会导致死锁问题,因此InnoDB存储引擎使用一种称为wait-forgraph的方法来自动检测死锁。锁,事务自动回滚。接下来,我们来看一个MySQL中的死锁案例。第一步:打开终端A,登录MySQL,设置事务隔离级别为可重复读,事务启动后对账户数据表中id为1的数据加排他锁,如下图。mysql>setsessiontransactionisolationlevelrepeatableread;QueryOK,0rowsaffected(0.00sec)mysql>starttransaction;QueryOK,0rowsaffected(0.00sec)mysql>select*fromaccountwhereid=1forupdate;+----+------+--------+|id|name|balance|+----+-------+--------+|1|张三|300|+----+--------+--------+1rowinset(0.00sec)第二步:打开终端B,登录MySQL,设置事务隔离级别为可重复读,启动事务为Add对account数据表中id为2的数据进行独占锁,如下图。mysql>setsessiontransactionisolationlevelrepeatableread;QueryOK,0rowsaffected(0.00sec)mysql>starttransaction;QueryOK,0rowsaffected(0.00sec)mysql>select*fromaccountwhereid=2forupdate;+----+------+--------+|id|name|balance|+----+-------+--------+|2|Lisi|350|+----+--------+--------+1rowinset(0.00sec)第三步:对A端account数据表中id为2的数据加排他锁,如下图。mysql>select*fromaccountwhereid=2forupdate;此时线程会一直卡住,因为它在等待B端id为2的数据释放排他锁。第四步:对B端账户数据表中id为1的数据加排他锁,如下图。mysql>select*fromaccountwhereid=1forupdate;ERROR1213(40001):Deadlockfoundwhentryingtogetlock;tryrestartingtransaction此时发生死锁。使用以下命令查看死锁的日志信息。showengineinnodbstatus\G通过命令行查看LATESTDETECTEDDEADLOCK选项的相关信息,可以找到死锁的相关信息,或者配置innodb_print_all_deadlocks(MySQL5.6.2后可用)参数为ON打印死锁相关信息到MySQL错误日志中间。在MySQL中,通常通过以下方式避免死锁。尽量让数据表中的数据检索通过索引来完成,避免无效索引将行锁升级为表锁。合理设计索引,尽量减少锁的范围。尽量减少查询条件的范围,尽量避免间隙锁或者缩小间隙锁的范围。尽量控制事务的大小,减少事务锁定资源的数量,缩短锁定资源的时间。如果SQL语句涉及事务加锁操作,尽量在整个事务结束时执行。尽可能使用低级事务隔离机制。作者简介:肖宇,分布式事务架构专家,Apache神鱼(孵化)网关创始人,Dromara开源组织创始人,Hmily、RainCat、Myth等分布式事务框架作者。阿帕奇ShardingSphere提交者。冰河,资深互联网技术专家,MySQL技术专家,分布式事务架构专家。多年来一直致力于分布式系统架构、微服务、分布式数据库、分布式事务和大数据技术的研究,在高并发、高可用性、高扩展性、高可维护性和大数据领域具有专长。丰富的建筑经验。本文节选自《深入理解分布式事务:原理与实战》,经发布者授权发布。
