我使用的是PostgreSQL 9.2,我没有在任何地方使用显式锁定,既没有使用LOCK
语句也没有使用SELECT ... FOR UPDATE
。然而,最近我遇到了ERROR: 40P01: 死锁检测到
。尽管死锁检测到的查询被包装在事务块中,但是为什么会出现这种情况呢?
我使用的是PostgreSQL 9.2,我没有在任何地方使用显式锁定,既没有使用LOCK
语句也没有使用SELECT ... FOR UPDATE
。然而,最近我遇到了ERROR: 40P01: 死锁检测到
。尽管死锁检测到的查询被包装在事务块中,但是为什么会出现这种情况呢?
你不需要任何显式的LOCK
来进入死锁状态。以下是一个非常简单的演示,仅使用INSERT语句:
create table a(i int primary key);
create table b(i int primary key);
第一次会话执行以下操作:
begin;
insert into a values(1);
然后第二个会话执行:
begin;
insert into b values(1);
insert into a values(1);
-- here it goes into waiting for session #1 to finish its transaction
然后第一次会话执行以下操作:
insert into b values(1);
然后死锁发生:
错误: 检测到死锁
详细信息: 进程9571等待事务4150上的ShareLock;被进程9501阻塞。
进程9501等待事务4149上的ShareLock;被进程9571阻塞。
提示: 请查看服务器日志以获取查询详细信息。
简单的UPDATE或UPDATE和INSERT的组合也可能发生相同的情况。这些操作会获取隐式锁,如果它们在不同会话中以不同顺序进行,它们可能会导致死锁。
我首先怀疑哈希索引问题。
hash
索引转换为B-tree
索引Serializable
隔离级别。