什么是数据库死锁在操作系统领域,死锁是指两个或多个正在运行的进程,由于争夺公共访问资源而相互阻塞,最终导致进程无法运行接着说。执行的阻塞现象。那么数据库领域的死锁是什么形式呢?数据库死锁会导致什么样的问题?在了解数据库死锁之前,我们先来明确一下什么是数据库锁?有Java编程经验的同学都知道,Java中的锁是为了解决并发访问共享数据的安全问题,防止并发访问造成共享数据混乱。那么在数据库领域,数据库中的锁是干什么用的呢?其实数据库也是用来解决并发问题的。如果同时可能有多个事务对同一张表中的同一个字段进行数字加减运算,没有任何控制措施,也会导致各种数据一致性问题。因此,数据库的锁实际上是一种保证数据一致性和控制可能的并发操作的手段。下面举例说明,假设有两个这样的交易,交易A包含如下语句:UPDATEuserSETname='小木'id=1UPDATEproductSETprice=price*10WHEREid=2交易B包含如下语句:UPDATEproductSETprice=price*100WHEREid=2UPDATEuserSETname='Xiaofeng'WHEREid=1如果这两个交易并发执行,那么它们可能有如下执行条件。事务A执行时,首先运行查询语句:UPDATEuserSETname='小木'id=1相当于事务A对id为1的数据行加了排他锁,但是事务还没有执行,也就是说即事务A持有用户表id为1的排他锁,排他锁的特点是此时其他事务无法删除或修改数据,所以只能在事务结束后再次获取锁发行了。此时事务B执行update语句获取product表id为2的排他锁,然后事务B开始执行user表的update语句,需要获取id为2的排他锁在用户表中为1。但是此时事务A还没有提交,所以事务A持有表user的id为1的独占锁,事务B只能乖乖的阻塞等待事务A释放锁。此时事务A在执行update语句时,需要获取id为产品2的排他锁,但是此时事务B持有排他锁,所以还需要等待事务的释放堵塞。UPDATEproductSETprice=price*10WHEREid=2事务A在等待事务B释放锁,事务B在等待事务A释放锁,最后陷入互相等待的境地,这就是所谓的死锁。那么数据库死锁会导致哪些问题呢?数据库死锁会导致严重的性能问题。平台可能因数据库死锁导致运行缓慢,严重影响用户正常使用业务。因此,如果发生数据库死锁,需要及时发现并很好地解决。定位死锁//首先判断数据库是否存在死锁select*frompg_stat_activitywheredatname='product_db';//查询可能被锁的表的oidselectoidfrompg_classwhererelname='product';//查询对应的pidselectpidfrompg_lockswhererelation='oid'//上面查询到的oid//取消或终止对应进程破坏死锁条件selectpg_cancel_backend(pid);selectpg_terminate_backend(pid);死锁的可能原因及解决办法上面的分析了解了如何定位分析PostgreSQL死锁后,接下来就要总结分析PostgreSQL死锁的原因及一般解决办法。1、索引使用不当导致的死锁问题。如果索引使用出现问题,就会导致死锁问题。假设在一个数据查询事务中,在进行数据检索的时候,没有办法根据SQL中的where条件进行查询,从而导致全表扫描,那么数据库表的行级锁就会升级为表此时锁定级别。如果此时有多个事务无法根据where条件进行数据查询,很容易造成数据库死锁。也就是说,当数据库表的数据量比较大时,数据查询对应的表还没有建立索引或者索引创建不合理,导致无法通过索引进行数据查询,只能可以使用全表索引。在这样的场景下,很容易发生死锁。如何避免:在进行数据查询时,对应的SQL语句不要过于复杂,即尽量避免多表的关联查询。2.不同事务之间的访问顺序问题当用户A访问数据库表A时,此时在表A上加了一个共享锁,然后访问数据库表B。此时另一个用户B访问表B,加了一个共享锁锁定到表B,然后尝试访问表A。但是,由于用户B已经锁定了表B,用户A必须等待用户B释放表B才能继续。同样,用户B必须等待用户A释放表A才能继续,也就是说,互相等待对方释放资源,造成死锁。发生了。如何避免:这种情况在很多实际项目中可能会遇到。主要是需要控制代码的执行逻辑,避免多表操作时同时锁定多个资源。避免死锁的建议(1)如果平台有大笔交易,尽量拆分成小笔交易。因为大事务一般会对大量的数据库表或数据进行操作,造成死锁或阻塞的概率比较高。(2)为数据库表设计合理的索引,数据查询时尽量避免索引未被覆盖或索引无效的情况,因为全表扫描会导致表中的数据行被锁定,这大大增加了数据库死锁的概率。(3)如果业务允许,我们可以尝试降低隔离级别,比如将隔离级别从RR调整为RC,这样可以避免很多间隙锁带来的死锁。(4)在我们自己的代码中,尽量以一致的顺序获取对象上的锁,避免SQL在事务中交互执行,从而降低死锁的概率。
