【问题标题】:How to manually lock and unlock a row?如何手动锁定和解锁一行?
【发布时间】:2014-05-16 18:28:30
【问题描述】:

我试图通过锁定和解锁某些行来规避双重写入。

我有一个表personnel,一旦用户尝试编辑一行,我想锁定该行。

所以

BEGIN;
// I guess I have to lock it somehow here
SELECT * FROM personnel WHERE id = 12;
COMMIT;

一旦进行了编辑,我想以相同的样式提交UPDATE

BEGIN;
//Unlocking
UPDATE personnel SET ...
WHERE id = 12;
COMMIT;

在此期间,当另一个用户尝试编辑同一行时,他会收到一条消息。

【问题讨论】:

标签: postgresql concurrency transactions sql-update


【解决方案1】:

锁在事务结束时被释放。因此,您需要保持事务打开以保持锁定并在单个事务中完成所有操作:

BEGIN;
SELECT * FROM personnel WHERE id = 12 FOR UPDATE NOWAIT;  -- row level locking
COMMIT;

BEGIN;
UPDATE personnel SET ...
WHERE id = 12;
COMMIT;

或者,您可以使用限制较少的FOR SHARE 子句。
Details in the manual on SELECT in the chapter "The Locking Clause".

允许并发读取。引用章节"Row-level Locks" in the manual

除了表级锁,还有行级锁,可以 是排他锁或共享锁。一个独占的行级锁 更新行时自动获取特定行或 删除。锁一直保持到事务提交或回滚, 就像表级锁一样。行级锁不影响数据 查询;他们只阻止同一行的作者

要同时尝试立即失败,请使用 NOWAIT 选项 - 对于所有竞争查询。

【讨论】:

  • 在我执行SELECT 之后,我仍然可以从另一个 psql 终端访问该行。这应该是不可能的。
  • 好的 FOR UPDATE 阻止有关该行的新更新,但即使来自 SELECT 也无法阻止该行?
  • @Saphire:是的,这是设计使然。允许并发读取。
  • 我的意思是这个在此期间,当另一个用户尝试编辑同一行时,他会收到一条消息。
  • @Saphire:另一个用户应该使用相同的代码,并且必须等到锁被释放(第一个事务完成)或超时。如果您不想等待,但收到错误消息,请使用NOWAIT
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多