您的当前位置:首页正文

[整理]数据库死锁的产生原因及解决办法(基于mysql)

2023-11-25 来源:易榕旅网
[整理]数据库死锁的产⽣原因及解决办法(基于mysql)

数据库和操作系统⼀样,是⼀个多⽤户使⽤的共享资源。当多个⽤户并发地存取数据时,在数据库中就会产⽣多个事务同时存取同⼀数据的情况。

如果对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的⼀致性。加锁是实现数据库并发控制的⼀个⾮常重要的技术。

在实际应⽤中经常会遇到的与锁相关的异常情况,当两个事务需要⼀组有冲突的锁,⽽不能将事务继续下去的话,就会出现死锁,严重影响应⽤的正常执⾏。

在数据库中有两种基本的锁类型:排它锁(Exclusive Locks,即X锁)和共享锁(Share Locks,即S锁)。

当数据对象被加上排它锁时,其他的事务不能对它读取和修改。加了共享锁的数据对象可以被其他事务读取,但不能修改。数据库利⽤这两种基本的锁类型来对数据库的事务进⾏并发控制。

⼀、死锁的第⼀种情况

⼀个⽤户A 访问表A(锁住了表A),然后⼜访问表B;另⼀个⽤户B 访问表B(锁住了表B),然后企图访问表A;这时⽤户A由于⽤户B已经锁住表B,它必须等待⽤户B释放表B才能继续,同样⽤户B要等⽤户A释放表A才能继续,这就死锁就产⽣了。解决⽅法:

这种死锁⽐较常见,是由于程序的BUG产⽣的,除了调整的程序的逻辑没有其它的办法。仔细分析程序的逻辑,对于数据库的多表操作时,尽量按照相同的顺序进 ⾏处理,尽量避免同时锁定两个资源,如操作A和B两张表时,总是按先A后B的顺序处理, 必须同时锁定两个资源时,要保证在任何时刻都应该按照相同的顺序来锁定资源。

⼆、死锁的第⼆种情况

⽤户A查询⼀条纪录,然后修改该条纪录;这时⽤户B修改该条纪录,这时⽤户A的事务⾥,锁的性质由查询的共享锁企图上升到独占锁,⽽⽤户B的独占锁由于A有共享锁存在所以必须等A释放掉共享锁,⽽A由于B的独占锁⽽⽆法上升的独占锁也就不可能释放共享锁,于是出现了死锁。这种死锁⽐较隐蔽,但在稍⼤点的项⽬中经常发⽣。如在某项⽬中,页⾯上的按钮点击后,没有使按钮⽴刻失效,使得⽤户会多次快速点击同⼀按钮,这样同⼀段代码对数据库同⼀条记录进⾏多次操作,很容易就出现这种死锁的情况。解决⽅法:

1. 对于按钮等控件,点击后使其⽴刻失效,不让⽤户重复点击,避免对同时对同⼀条记录操作。2. 使⽤乐观锁进⾏控制。乐观锁⼤多是基于数据版本(Version)记录机制实现。

即为数据增加⼀个版本标识,在基于数据库表的版本解决⽅案中,⼀般是通过为数据库表增加⼀个“version”字段来实现。

读取出数据时,将此版本号⼀同读出,之后更新时,对此版本号加⼀。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进⾏⽐对,如果提交的数据版本号⼤于数据库表当前版本号,则予以更新,否则认为是过期数据。乐观锁机制避免了长事务中的数据库加锁开销(⽤户A和⽤户B操作过程中,都没有对数据库数据加锁),⼤⼤提升了⼤并发量下的系统整体性能表现。Hibernate在其数据访问引擎中内置了乐观锁实现。需要注意的是,由于乐观锁机制是在我们的系统中实现,来⾃外部系统的⽤户更新操作不受我们系统的控制,因此可能会造成脏数据被更新到数据库中。

3. 使⽤悲观锁进⾏控制。悲观锁⼤多数情况下依靠数据库的锁机制实现,如Oracle的Select … for update语句,以保证操作最⼤程度的独占性。但随之⽽来的就是数据库性能的⼤量开销,特别是对长事务⽽⾔,这样的开销往往⽆法承受。

如⼀个⾦融系统,当某个操作员读取⽤户的数据,并在读出的⽤户数据的基础上进⾏修改时(如更改⽤户账户余额),如果采⽤悲观锁机制,也就意味着整个操作过程中(从操作员读 出数据、开始修改直⾄提交修改结果的全过程,甚⾄还包括操作员中途去煮咖啡的时间),数据库记录始终处于加锁状态,可以想见,如果⾯对成百上千个并发,这样的情况将导致灾难性的后果。所以,采⽤悲观锁进⾏控制时⼀定要考虑清楚。三、死锁的第三种情况

如果在事务中执⾏了⼀条不满⾜条件的update语句,则执⾏全表扫描,把⾏级锁上升为表级锁,多个这样的事务执⾏后,就很容易产⽣死锁和阻塞。类似的情况还有当表中的数据量⾮常庞⼤⽽索引建的过少或不合适的时候,使得经常发⽣全表扫描,最终应⽤系统会越来越慢,最终发⽣阻塞或死锁。解决⽅法:

SQL语句中不要使⽤太复杂的关联多表的查询;使⽤“执⾏计划”对SQL语句进⾏分析,对于有全表扫描的SQL语句,建⽴相应的索引进⾏优化。

四、⼩结

总体上来说,产⽣内存溢出与锁表都是由于代码写的不好造成的,因此提⾼代码的质量是最根本的解决办法。

有的⼈认为先把功能实现,有BUG时再在测试阶段进⾏修正,这种想法是错误的。正如⼀件产品的质量是在⽣产制造的过程中决定的,⽽不是质量检测时决定的,软件的质量在设计与编码阶段就已经决定了,测试只是对软件质量的⼀个验证,因为测试不可能找出软件中所有的BUG。

因篇幅问题不能全部显示,请点此查看更多更全内容