Postgresql共享行独占锁VS pg_advisory_lock

时间:2015-03-05 22:27:46

标签: postgresql locking deadlock psycopg2 postgresql-9.3

我正在运行Postgres 9.3并有一个表标签,可通过Python的psycopg2模块访问。我有一个名为'tags'的表,它通过两种不同的方法更新/插入,称为'update'和'insert'。我还有几个同时运行的工作程序,每个工作程序都调用'update'或'insert'。由于唯一性约束,我想在执行插入或更新之前直接锁定'tags'表,然后我直接提交事务。

所以我的代码大致看起来像(用psycopg2说法)

更新:

cur.execute(LOCK TABLE tags IN SHARE ROW EXCLUSIVE MODE)
cur.execute(UPDATE tags SET ...)
cur.execute(DELETE FROM tags ....)
cur.execute(INSERT INTO tags ...)
connection.commit()

INSERT:

cur.execute(LOCK TABLE tags IN SHARE ROW EXCLUSIVE MODE)
cur.execute(DELETE FROM tags ....)
cur.execute(INSERT INTO tags ...)
connection.commit()

我的架构看起来像

user_id varchar NOT NULL, 
tag varchar NOT NULL, 
time timestamptz, 
CONSTRAINT unique_tag_key PRIMARY KEY (user_id, tag)
CONSTRAINT seen_before_user FOREIGN_KEY (user_id)
    REFERENCES user_id_table (user_id) MATCH SIMPLE 
    ON UPDATE NO ACTION ON DELETE NO ACTION 

我遇到的问题是,当我运行并发工作程序时,我会在执行共享锁时遇到死锁。 奇怪的是,如果我用类似

的调用替换LOCK TABLE调用
cur.execute("SELECT pg_advisory_lock(tag_hash)")

其中tag_hash是标签表名称'tags'上的哈希值,我没有遇到这样的错误。

为什么我在SHARE ROW EXCLUSIVE中遇到错误,而不是pg_advisory锁?如果我能保证在这两种方法之外永远不会修改标签表,那么在这里使用pg_advisory锁是否有任何缺点?

1 个答案:

答案 0 :(得分:0)

我认为你这样做是错误的。

  1. 除非您在其上运行DDL,否则永远不应该锁定Postgres中的整个表。

  2. 您对相关字段

  3. 已有唯一约束

    您最好的选择是尝试/除外。如果存在异常对于约束违规 - 正确处理它或检测到死锁异常,只需重试即可。

    一般来说,postgres非常适合处理锁而不需要手动锁定控制,除非你做的事非常疯狂。