【问题标题】:lock a transaction (series of selects and updates) in Postgresql在 Postgresql 中锁定事务(一系列选择和更新)
【发布时间】:2014-01-14 08:48:49
【问题描述】:

我有一个表和几个线程(系统),它们从表中读取特定列并更新它。所以我的查询如下:

Begin;
SELECT col FROM tbl WHERE <condition1>
UPDATE tbl SET col = col + 1 WHERE <condition1>
Commit;

我想确保在任何时候只有一个线程可以选择和更新该列。什么是最好的解决方案?

PS:据我所知,在 SQL Server 中使用事务会锁定事务中的所有资源,但我不知道 PostgreSQL。

谢谢!

【问题讨论】:

    标签: postgresql locking


    【解决方案1】:

    SQL 中最高级的锁是行锁。

    无法锁定列,数据库总是在整行(该行的所有列)上加锁。

    你可以使用a SELECT .. FOR UPDATE clause:

    Begin;
    SELECT col FROM tbl WHERE <condition1> FOR UPDATE;
    UPDATE tbl SET col = col + 1 WHERE <condition1> ;
    Commit;
    

    SELECT .. FOR UPDATE 的工作方式与普通的 select 类似(它从表中检索行),但另外它会锁定所有检索到的行,防止它们被其他事务修改,直到当前事务结束。

    你也可以使用RETURNING clause in UPDATE statement

    Begin;
    UPDATE tbl SET col = col + 1 WHERE <condition1> 
       RETURNING col - 1 AS col;
    Commit;
    

    UPDATE 语句总是在修改的记录上放置一个写锁。

    RETURNING 子句导致返回值,和普通的SELECT 一样,但是它返回修改后的行值(更新后的行值),因此在上面的示例中使用了col - 1 表达式来计算增加之前的列值。

    请看一下这个演示 --> http://www.sqlfiddle.com/#!15/4d0f4/3

    第二种方式(UPDATE+RETURNING子句)的优点是记录只被访问一次,相对于第一种方式,当行必须先被SELECT语句选中时(第一次访问),那么它使用UPDATE 语句更新(第二次访问)。

    【讨论】:

    • 感谢 kordirko!您的解决方案非常好,但它不会阻止从该行读取。我经历了几个解决方案,最后在阅读 PostgreSQL 手册后,我发现使用“LOCK TABLE tbl IN ACCESS EXCLUSIVE MODE”可以帮助您锁定表以进行读写。 (我连续找不到任何东西)
    【解决方案2】:

    kordirko 已正确指出 SELECT ... FOR UPDATE 是用于此目的的基本功能。

    请注意,它不会使用谓词锁。所以如果你SELECT id FROM sometable WHERE id = 42 FOR UPDATE 并且没有id = 42 的行,没有锁定。没有在 ID 42 上创建“保留”。其他人可以在您的 SELECT 和随后的 INSERT 之间创建它。

    如果您想解决这个问题,您可能希望查看SERIALIZABLE 隔离模式。我认为您习惯的 MS SQL Server 默认为 SERIALIZABLE 隔离。

    您可以改为:

    BEGIN ISOLATION LEVEL SERIALIZABLE;
    SELECT col FROM tbl WHERE <condition1>
    UPDATE tbl SET col = col + 1 WHERE <condition1>
    COMMIT;
    

    我强烈建议设置一些并发测试来证明这当然可以按您的预期工作。

    【讨论】:

    • 嗨克雷格,感谢您的解释。我认为你是对的,默认情况下 MS SQL 事务是可序列化的。我还阅读了 PostgreSQL 手册,发现表有一个高级锁,可以防止任何读写“LOCK TABLE chunk_prop IN ACCESS EXCLUSIVE MODE”。您对此解决方案与您的解决方案的性能有什么想法吗?再次感谢您
    • @MajidDarabi ACCESS EXCLUSIVE 锁既快速又便宜,只要您不介意完全阻止对表的所有其他访问。您消除了 table 级别的所有并发,而不仅仅是行级别。因此,如果您的更新很少,则可以很好地使用它,但是如果您有很多更新,则会给您带来很大的痛苦。 EXCLUSIVE MODE 只阻止写入者,而不阻止读取者,并且稍微不那么痛苦,但仍然没有给你写并发。真的取决于你的工作量,所以像往常一样,这是一个测试和观察的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-22
    • 2014-05-14
    • 1970-01-01
    • 1970-01-01
    • 2017-08-18
    相关资源
    最近更新 更多