从这个question开始,我想使用以下方法在PostGreSql表中执行upsert:
UPDATE table SET field='C', field2='Z' WHERE id=3;
INSERT INTO table (id, field, field2)
SELECT 3, 'C', 'Z'
WHERE NOT EXISTS (SELECT 1 FROM table WHERE id=3);
我知道我必须在事务中执行它并且我应该使用显式锁定方法。我一直在阅读postgresql文档,但我仍然在三种类型的锁之间犹豫不决(每种锁的区别对我来说都不是很清楚):
ROW EXCLUSIVE
SHARE ROW EXCLUSIVE
EXCLUSIVE
我想避免重试交易。我并不期望在行上有太多的并发性,尽管这可能会不时发生。在极少数情况下,可能会同时尝试删除和插入同一行。
答案 0 :(得分:2)
您需要自包含锁定类型,排除所有DML命令。
此操作的正确锁定类型为EXCLUSIVE
。它与所有其他锁冲突,包括其自身,除 ACCESS SHARE
。
ACCESS SHARE
由SELECT
拍摄。所有其他命令需要更高的锁定级别。因此,您的upsert事务将阻止除SELECT
之外的所有内容,这就是您想要的内容。
请参阅the docs on explicit locking。
所以:
BEGIN;
LOCK TABLE ... IN EXCLUSIVE MODE;
...
(使用单词ROW
对某些表级锁定进行历史记录和可怕的命名并不能简化对PostgreSQL锁类型的理解。
顺便说一下,您的应用程序应该检查从UPDATE
返回的行数。如果它不为零,则可以跳过INSERT
。