我对Postgres足够陌生,并且试图弄清楚如何锁定表的特定行。
例如,我有一个用户表:
Name: John, Money: 1
Name: Jack, Money: 2
在后端,我想选择John,并确保在我的交易完成之前,没有其他电话可以更新(甚至可能选择)John的行。
我想我需要从网上阅读的书中获得排他锁吗?我似乎找不到一个很好的示例,可以在线锁定一个表中的仅1行,知道吗?
编辑-我应该在@SqlUpdate之类的方法级别(或使用org.skife.jdbi.v2的某种形式)还是在查询本身中执行此操作?
答案 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>