当前位置: 首页 > 知识库问答 >
问题:

在Postgresql中锁定事务(一系列选择和更新)

郭阳曜
2023-03-14

我有一个表和几个线程(系统),它们从表中读取特定列并更新它。因此,我的问题如下:

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

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

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

非常感谢。

共有2个答案

葛嘉悦
2023-03-14

科迪尔科正确地指出,SELECT。。。FOR UPDATE是用于此操作的基本功能。

请注意,它不会使用谓词锁。因此,如果您从id=42的某个表中选择id进行更新,并且没有id=42的行,则不会进行锁定。没有在ID 42上创建“预订”。其他人可以跳入并在您的选择和后续的插入之间创建它。

如果您正试图解决这个问题,您可能希望查看SERIALIZABLE隔离模式。我认为MSSQLServer,您已经习惯了,默认为SERIALIZABLE隔离。

你可以改写:

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

当然,我强烈建议设置一些并发测试来证明这是您所期望的。

黄德明
2023-03-14

SQL最好的级别锁是行锁。

无法锁定列,数据库始终会锁定整行(该行的所有列)。

您可以使用SELECT...FOR UPDATE子句:

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

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

还可以在UPDATE语句中使用RetURning子句:

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

UPDATE语句始终在修改的记录上放置写锁。

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

请看一下这个演示

第二种方法(UPDATETREURning子句)的优点是,与第一种方法相反,当行必须首先由SELECT语句(第一次访问)选择时,记录只被访问一次,然后使用UPDATE语句(第二次访问)。

 类似资料:
  • 这是我的伪代码: 我想问,如果条件等于“key”的行已经被删除,那么“select for update”阻止的锁是否可以自动解锁,这意味着如果另一个进程在此点进入并选择相同的“key”,它就不能被此进程阻止?

  • 问题内容: 我有一个可以支持一定数量的并发操作的应用程序。这由postgres中的“插槽”表表示。当节点联机时,它们会在表中插入许多行,每个插槽一个。当作业声明插槽时,它们会更新表中声明其中一个插槽的行,并在完成时再次释放它。 插槽表如下所示: 在任何时候,它都有一些固定的行数,每行可以或可以不填写job_name。 当新作业要启动时,它将运行以下查询以获取应在其上运行的节点的名称: (从游标中读

  • 问题内容: 有时,对于仅作为Select查询的存储过程,会出现以下错误: 我最初的理解是,选择查询不会锁定表,也不会导致死锁,即使它试图查询的表正在被另一个进程更新/锁定,但似乎选择查询会导致死锁,因为出色地。 如果我将隔离级别设置为查询未提交,那可以解决问题吗? 问题答案: 我的初步理解是,Select查询不会锁定表,也不会导致死锁 这种理解是错误的。SELECT查询在其分析的行上使用共享锁。共

  • 我想编写一个简单的查询来选择PostgreSQL中的许多列。但是,我一直收到错误-我尝试了几个选项,但它们对我不起作用。目前我收到以下错误: 组织。postgresql。util。PSQLException:错误:“列”处或附近出现语法错误 要获取具有值的列,请尝试以下操作: 有什么想法吗?

  • 问题内容: 希望有一些比我更聪明的DBA,可以帮助我找到所需做的很好的解决方案。 为了便于讨论,假设我有一个名为“ work”的表,其中包含一些列,其中之一是代表来自给定客户端的该行工作的所有权的列。场景是我将连接2个客户端,并轮询一个表以完成工作,当显示一行(或一定数量的行)时,选择该行的第一个客户端也将对其进行更新以暗示所有权,即更新将删除那些返回给其他任何客户选择内容的行。我的问题是,在这种

  • 我有一个用户批次表。我只想选择,直到我的总金额达到一定金额。 考虑以下查询: 查询结果为: 我想在表格上做一个选择,直到余额总数为6。然后只返回id 1,2: 余额总计为1的另一个示例。那么应该只返回ids 1: 余额合计为11的示例。应该只返回ids,3,4: 所以,在那之后,我需要用FORUPDATE ex锁定这些行: 我尝试了窗口功能,但它不允许锁定(更新)。感谢任何帮助。