锁定Postgres中的特定行

时间:2018-06-23 15:56:28

标签: sql postgresql

我对Postgres足够陌生,并且试图弄清楚如何锁定表的特定行。

例如,我有一个用户表:

Name: John, Money: 1
Name: Jack, Money: 2

在后端,我想选择John,并确保在我的交易完成之前,没有其他电话可以更新(甚至可能选择)John的行。

我想我需要从网上阅读的书中获得排他锁吗?我似乎找不到一个很好的示例,可以在线锁定一个表中的仅1行,知道吗?

编辑-我应该在@SqlUpdate之类的方法级别(或使用org.skife.jdbi.v2的某种形式)还是在查询本身中执行此操作?

3 个答案:

答案 0 :(得分:4)

一旦您更新(而不是提交)该行,其他任何事务都将无法更新该行。

如果您想在执行更新之前将行锁定在 (这似乎没有用),则可以使用select ... for update

您不能阻止其他会话读取该行,坦率地说,这也没有道理。

即使您的事务尚未完成(已提交),其他会话也将看到任何中间(不一致)值-他们将看到事务开始之前的数据库状态。这就是拥有支持事务的关系数据库的全部意义。

答案 1 :(得分:2)

如果要将表锁定在特定的选定行中,则需要LOCK FIRST使用FOR UPDATE / FOR SHARE语句。 例如,如果您需要锁定第一行,请执行以下操作:

BEGIN;

LOCK TABLE person IN ROW EXCLUSIVE MODE;

-- BLOCK 1

SELECT * FROM person WHERE name = 'John' and money = 1 FOR UPDATE;

-- BLOCK 2

UPDATE person set name = 'John 2' WHERE name = 'John' and money = 1;

END;

BLOCK1语句之前的SELECT中,您什么都不做,只是告诉数据库“嘿,我将在此表中执行某项操作,因此,当执行此操作时,请以这种方式锁定此表”。您可以选择/更新/删除任何行。

但是在BLOCK2中,当您使用FOR UPDATE时,会将该行锁定到特定模式的其他事务(有关详细信息,请阅读doc)。在交易结束之前将被锁定。

如果您需要一个示例,请进行测试,然后尝试在SELECT ... FOR UPDATE中执行另一个BLOCK2,然后结束第一笔交易。它将等待第一笔交易结束,并在其后立即选择。

  

只有ACCESS EXCLUSIVE锁会阻止SELECT(不包含FOR   UPDATE / SHARE)语句。

我在函数中使用它来控制子序列,这很棒。希望你喜欢。

答案 2 :(得分:1)

您可以使用

LOCK TABLE table IN ACCESS EXCLUSIVE MODE;

当您准备从表中读取数据时。 “ SELECT”和所有其他操作将一直排队直到事务结束(提交更改或回滚)。

请注意,这将锁定整个表,而对于PostgreSQL,则没有表级锁可以专门锁定特定的行。

因此您可以使用

FOR UPDATE 

将行选择锁定在将更新行的所有SELECT中,这将阻止所有将更新行的SELECT读取行!

PostgreSQL文档:

FOR UPDATE 导致SELECT语句检索的行被锁定,就像要进行更新一样。这样可以防止它们被其他事务锁定,修改或删除,直到当前事务结束为止。也就是说,将阻止其他尝试进行这些行的UPDATE,DELETE,SELECT FOR UPDATE,SELECT FOR NO KEY UPDATE,SELECT FOR SHARE或SELECT FOR KEY SHARE的事务,直到当前事务结束为止。相反,SELECT FOR UPDATE将等待在同一行上运行了任何这些命令的并发事务,然后将锁定并返回更新的行(如果删除了该行,则不返回任何行)。但是,在REPEATABLE READ或SERIALIZABLE事务中,如果自事务开始以来要锁定的行已更改,则将引发错误。有关更多讨论,请参见第13.4节。

FOR UPDATE锁定模式还可以通过行上的任何DELETE以及修改某些列上的值的UPDATE来获取。当前,在UPDATE情况下考虑使用的列集是那些可以在外键上使用的唯一索引的列(因此不考虑部分索引和表达式索引),但是将来可能会改变。 / p>