数据库锁表及阻塞的缘由和解决办法

问题说明java

当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的状况。若对并发操做不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。加锁是实现数据库并发控制的一个很是重要的技术。在实际应用中常常会遇到的与锁 相关的异常状况,当两个事务须要一组有冲突的锁,而不能将事务继续下去的话,就会出现死锁,严重影响应用的正常执行。 
在数据库中有两种基本的锁类型:排它锁(Exclusive Locks,即X锁)和共享锁(Share Locks,即S锁)。当数据对象被加上排它锁时,其余的事务不能对它读取和修改。加了共享锁的数据对象能够被其余事务读取,但不能修改。数据库利用这两 种基本的锁类型来对数据库的事务进行并发控制。 
关于共享锁和排他锁总结: 
1mysql InnoDB引擎默认的修改数据语句,update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁类型 
2排他锁不能和其余锁共存 
3共享锁能够和其余锁共存(因为排他锁的特性,共享锁只能和共享锁共存) 
mysql

死锁的第一种状况sql

一个用户A 访问表A(锁住了表A),而后又访问表B;另外一个用户B 访问表B(锁住了表B),而后企图访问表A;这时用户A因为用户B已经锁住表B,它必须等待用户B释放表B才能继续,一样用户B要等用户A释放表A才能继续,这就死锁就产生了。数据库

解决方法markdown

这种死锁比较常见,是因为程序的BUG产生的,除了调整的程序的逻辑没有其它的办法。仔细分析程序的逻辑,对于数据库的多表操做时, 尽可能按照相同的顺序进行处理,尽可能避免同时锁定两个资源,如操做A和B两张表时,老是按先A后B的顺序处理, 必须同时锁定两个资源时,要保证在任什么时候刻都应该按照相同的顺序来锁定资源。并发


死锁的第二种状况post

用户A查询一条纪录,而后修改该条纪录;这时用户B修改该条纪录,这时用户A的事务里锁的性质由查询的共享锁企图上升到独占锁,而用户B里的独占锁因为A有共享锁存在因此必须等A释放掉共享锁,而A因为B的独占锁而没法上升的独占锁也就不可能释放共享锁,因而出现了死锁。这种死锁比较隐蔽,但在稍大点的项目中常常发生。如在某项目中,页面上的按钮点击后,没有使按钮马上失效,使得用户会屡次快速点击同一按钮,这样同一段代码对数据库同 一条记录进行屡次操做,很容易就出现这种死锁的状况。性能

解决方法优化

一、对于按钮等控件,点击后使其马上失效,不让用户重复点击,避免对同时对同一条记录操做。 
二、使用乐观锁进行控制。乐观锁大可能是基于数据版本(Version)记录机制实现。即为数据增长一个版本标识,在基于数据库表的版本解决 方案中,通常是经过为数据库表增长一个“version”字段来实现。读取出数据时,将此版本号一同读出,以后更新时,对此版本号加一。此时,将提交数据 的版本数据与数据库表对应记录的当前版本信息进行比对,若是提交的数据版本号大于数据库表当前版本号,则予以更新,不然认为是过时数据。乐观锁机制避免了 长事务中的数据库加锁开销(用户A和用户B操做过程当中,都没有对数据库数据加锁),大大提高了大并发量下的系统总体性能表现。hibernate 在其数据访问引擎中内置了乐观锁实现。须要注意的是,因为乐观锁机制是在咱们的系统中实现,来自外部系统的用户更新操做不受咱们系统的控制,所以可能会造 成脏数据被更新到数据库中。.net


死锁的第三种状况

若是在事务中执行了一条不知足条件的update语句,则执行全表扫描,把行级锁上升为表级锁,多个这样的事务执行后,就很容易产生死锁和阻塞。相似的状况还有当表中的数据量很是庞大而索引建的过少或不合适的时候,使得常常发生全表扫描,最终应用系统会愈来愈慢,最终发生阻塞或死锁。

解决方法

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

相关文章
相关标签/搜索