选择后postgres更新
Posted
技术标签:
【中文标题】选择后postgres更新【英文标题】:postgres update after select 【发布时间】:2011-10-09 11:20:37 【问题描述】:我想一次性完成以下操作:
SELECT * FROM jobs WHERE status='PENDING';
UPDATE jobs SET status='RUNNING' WHERE status='PENDING';
所以获取所有待处理的作业,然后立即将它们设置为“正在运行”。
我不想在两个语句中一个接一个地执行此操作的原因是,可以在 SELECT 之后但在 UPDATE 之前将作业作为“PENDING”添加到作业表中,因此我最终将作业设置为RUNNING 即使它处于 PENDING 状态时我还没有抓住它。
有没有办法合二为一?所以我希望 SELECT 和 UPDATE 的结果即时发生。
谢谢。
【问题讨论】:
【参考方案1】:为什么不使用 RETURNING 子句并在一个语句中处理这两个事情:
UPDATE jobs
SET status='RUNNING'
WHERE status='PENDING'
RETURNING *
这样,您将通过单个原子操作获取 UPDATE 更改的所有行。
【讨论】:
查看类似问答:***.com/questions/5636006/postgresql-and-locking/… 啊哈!当然,出于某种原因,我什至没有想到使用 RETURNING。谢谢。 如果您返回的不仅仅是一个表,而是与其他表的多个连接以及来自不同表的列,该怎么办?【参考方案2】:begin;
select *
from jobs
where status='pending'
for update
;
update jobs
set status='running'
where status='pending';
commit;
【讨论】:
我认为这些语句作为一个单元执行,第一条语句的输出是更新的输入,但我错了。如果您在第一个语句中添加了一个“AND”子句并在第二个语句中忽略了它......您将在数据库中进行灾难性的更新。仅在没有“提交”关键字的情况下尝试此操作,否则您会弄乱您的数据 就我而言,选择查询在表和计算上的连接和内连接非常复杂,我希望更新只是使用这些计算中的值来更新数据库值【参考方案3】:一般来说,您应该使用一个 UPDATE 语句来完成。 UPDATE 通常不会受到在 UPDATE 语句运行时可能已更改的行的影响,但是,最好阅读事务隔离级别 here。
假设您使用的是“已提交读”的默认设置,它是这样说的:
Read Committed 是 PostgreSQL 中的默认隔离级别。当一个 事务在此隔离级别上运行,SELECT 查询只能看到 在查询开始之前提交的数据;
关于更新:
UPDATE、DELETE、SELECT FOR UPDATE 和 SELECT FOR SHARE 命令 在搜索目标行方面的行为与 SELECT 相同:它们 只会找到在命令开始时提交的目标行 时间。但是,这样的目标行可能已经更新(或 被另一个并发事务删除或锁定) 成立。在这种情况下,可能的更新程序将等待第一个 更新事务以提交或回滚(如果它仍在 进步)。如果第一个更新程序回滚,那么它的效果是 否定,第二个更新程序可以继续更新 最初发现行。如果第一个更新者提交,第二个更新者 如果第一个更新程序删除了该行,将忽略该行,否则它将 尝试将其操作应用于行的更新版本。这 命令的搜索条件(WHERE 子句)被重新评估为 查看该行的更新版本是否仍然与搜索匹配 健康)状况。如果是这样,第二个更新程序继续其操作, 从行的更新版本开始。 (在选择的情况下 FOR UPDATE 和 SELECT FOR SHARE,表示它是更新版本 被锁定并返回给客户端的行。)
所以在你的场景中,一个 UPDATE 应该没问题。
还要记住,有一个称为SELECT FOR UPDATE
的语句,它将锁定您选择的行。你可以阅读here。
您需要使用此功能的场景是在预订系统中。考虑这个例子:
-
执行
SELECT
以查明房间 XYZ 是否可用于日期 X 的预订。
房间可用。执行UPDATE
查询预订房间。
您看到这里的潜在问题了吗?如果在第 1 步和第 2 步之间房间被另一笔交易预订,那么当 我们 到达第 2 步时,我们的操作假设不再有效,即房间可用。
但是,如果在第 1 步中我们改用 SELECT FOR UPDATE 语句,我们确保没有其他事务可以锁定该行,所以当我们去更新该行时,我们知道这样做是安全的。
但同样,在您的场景中,不需要此 SELECT FOR UPDATE,因为您在一个语句中执行所有操作并且没有提前检查任何内容。
【讨论】:
以上是关于选择后postgres更新的主要内容,如果未能解决你的问题,请参考以下文章
同步Postgres和ElasticSearch的最佳方法是什么?
Postgres SQL 触发器在 TableB 上插入或更新后使用新值更新 TableA.column
Postgres - 仅选择具有 FAILURE 状态的日期