Postgresql postgres在选择后更新

Postgresql postgres在选择后更新,postgresql,select,Postgresql,Select,我想一次完成以下工作: SELECT * FROM jobs WHERE status='PENDING'; UPDATE jobs SET status='RUNNING' WHERE status='PENDING'; 因此,获取所有挂起的作业,然后立即将它们设置为“正在运行” 我不想在两个语句中一个接一个地执行此操作的原因是,作业可以在SELECT之后但在更新之前作为“挂起”添加到作业表中,因此我会将作业设置为正在运行,即使它处于挂起状态时我没有抓取它 还有什么方法可以一次完成吗?因此,

我想一次完成以下工作:

SELECT * FROM jobs WHERE status='PENDING';
UPDATE jobs SET status='RUNNING' WHERE status='PENDING';
因此,获取所有挂起的作业,然后立即将它们设置为“正在运行”

我不想在两个语句中一个接一个地执行此操作的原因是,作业可以在SELECT之后但在更新之前作为“挂起”添加到作业表中,因此我会将作业设置为正在运行,即使它处于挂起状态时我没有抓取它

还有什么方法可以一次完成吗?因此,我希望SELECT的结果和更新能够实时进行


谢谢。

一般来说,你应该用一条更新语句来完成。在UPDATE语句运行时,更新通常不会受到可能已更改的行的影响,但是,最好读取事务隔离级别

假设您使用的是Read Committed的默认设置,下面是它的说明:

Read Committed是PostgreSQL中的默认隔离级别。当 事务在此隔离级别上运行,SELECT查询只能看到 查询开始前提交的数据

关于更新:

更新、删除、选择用于更新和选择用于共享命令 在搜索目标行方面的行为与SELECT相同:它们 将仅查找在命令start时提交的目标行 时间但是,这样的目标行可能已经更新(或 被另一个并发事务删除或锁定) 建立在这种情况下,可能的更新程序将等待第一次更新 正在更新要提交或回滚的事务(如果仍处于 进展)。如果第一个更新程序回滚,则其效果为 否定,第二个更新程序可以继续更新 原来发现了一排。如果第一个更新程序提交,则第二个更新程序 如果第一个更新程序删除了该行,则将忽略该行,否则将忽略该行 尝试将其操作应用于行的更新版本。这个 命令(WHERE子句)的搜索条件将重新计算为 查看行的更新版本是否仍与搜索匹配 条件如果是,则第二个更新程序继续其操作, 从行的更新版本开始。(如果是SELECT 对于更新,选择共享,这意味着它是更新版本 已锁定并返回给客户端的行的。)

因此,在您的场景中,一次更新就可以了

还请记住,有一个名为
selectforupdate
语句,它将锁定您选择的行。你可以读一下。 您需要使用此功能的场景是在预订系统中。考虑这个例子:

  • 执行
    选择
    ,查看XYZ房间是否可在X日预订
  • 房间空着。执行
    UPDATE
    query以预订房间
  • 你看到这里潜在的问题了吗?如果在第1步和第2步之间,房间被另一笔交易预订,那么当我们到达第2步时,我们的操作假设不再有效,即房间可用

    但是,如果在步骤1中改用SELECT FOR UPDATE语句,我们将确保没有其他事务可以锁定该行,因此当我们要更新该行时,我们知道这样做是安全的


    但是,在您的场景中,不需要此SELECT FOR UPDATE,因为您在一条语句中完成所有操作,并且没有提前检查任何内容。

    为什么不使用RETURNING子句并在一条语句中处理这两件事:

    begin;
    select * 
    from jobs 
    where status='pending'
    for update
    ;
    update jobs 
    set status='running' 
    where status='pending';
    commit;
    
    UPDATE jobs 
        SET status='RUNNING' 
    WHERE status='PENDING'
    RETURNING *
    

    这样,您将通过一个原子操作获得更新更改的所有行。

    请参阅类似的问题和答案:啊哈!当然,出于某种原因,我甚至没有想到使用RETURNING。谢谢。如果您返回的不仅仅是一个表,而是与其他表以及来自不同表的列的多个联接,该怎么办?我认为这些语句是作为单个单元执行的,第一个语句的输出是更新的输入,但我错了。如果您在第一条语句中添加了一个'AND'子句,而在第二条语句中忽略了它……那么您将面临数据库中的灾难性更新。请在不使用“Commit”关键字的情况下尝试此操作,否则会弄乱数据。对于我的情况,select查询与表和计算上的连接和内部连接非常复杂,我希望更新仅使用这些计算中的值来更新数据库值