我正在运行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锁是否有任何缺点?
答案 0 :(得分:0)
我认为你这样做是错误的。
除非您在其上运行DDL,否则永远不应该锁定Postgres中的整个表。
您对相关字段
您最好的选择是尝试/除外。如果存在异常对于约束违规 - 正确处理它或检测到死锁异常,只需重试即可。
一般来说,postgres非常适合处理锁而不需要手动锁定控制,除非你做的事非常疯狂。