我们有一个基于Web的应用程序.在应用程序中有时间限制的数据库操作(INSERT和UPDATE)需要更多的时间来完成,因此这个特定的流程已经被更改为
Java线程,所以它不会等待(块)完成数据库的完整操作.
我的问题是,如果有超过1个用户遇到这个特定的流,我面临的Postgresql抛出了以下错误:
org.postgresql.util.PsqlException: ERROR: deadlock detected Detail: Process 13560 waits for ShareLock on transaction 3147316424; blocked by process 13566. Process 13566 waits for ShareLock on transaction 3147316408; blocked by process 13560.
上述错误一直在INSERT语句中抛出.
附加信息:
1)我在此表中定义了PRIMARY KEY.
2)表中有FOREIGN KEY引用.
3)将单独的数据库连接传递给每个Java线程.
技术
Web服务器:Tomcat v6.0.10
Java v1.6.0
Servlet的
数据库:Postgresql v8.2.3
连接管理:pgpool II
解决方法
处理死锁的一种方法是具有等待随机间隔的重试机制,并尝试再次运行事务.随机间隔是必要的,以便碰撞事务不会持续地相互碰撞,导致所谓的实时锁 – 甚至更难调试.实际上,最复杂的应用程序在需要处理事务序列化失败时,迟早会需要这样的重试机制.
当然,如果你能够确定死锁的原因,通常会更好的消除它,否则会回来咬你.对于几乎所有的情况,即使死锁条件很少,吞吐量和编码开销的一点点就是以确定的顺序获得锁或获得更粗糙的锁,这是值得的,以避免偶然的大的延迟命中和突然的性能悬崖当缩放并发.
当您一直得到两个INSERT语句死锁时,很有可能是唯一的索引插入顺序问题.在两个psql命令窗口中尝试以下示例:
Thread A | Thread B BEGIN; | BEGIN; | INSERT uniq=1; INSERT uniq=2; | | INSERT uniq=2; | block waiting for thread A to commit or rollback,to | see if this is an unique key error. INSERT uniq=1; | blocks waiting | for thread B,| DEADLOCK | V
通常解决这个问题的最佳方法是找出保护所有这些事务的父对象.大多数应用程序都有一个或两个主要实体,如用户或帐户,这是一个很好的候选人.那么所有你需要的是每个事务通过SELECT … FOR UPDATE获得它所触摸的主实体上的锁.或者如果触摸几个,那么每次都获得锁定,但是每次都按同样的顺序(按主键排序是一个不错的选择).