在CTE中是否需要进行SELECT FOR UPDATE更新?

时间:2018-11-07 09:07:06

标签: postgresql

在PostgreSQL 9.6中,此CTE中下面的FOR UPDATE子句是否必要?

CREATE OR REPLACE FUNCTION next_job()
    RETURNS json
    LANGUAGE 'sql'

AS $BODY$

    WITH thejob AS (
        SELECT   jobs.*, company.*
        FROM     (
            select * from jobs 
            WHERE NOT EXISTS (SELECT * from jobs AS j2 where jobs.platform = j2.platform and jobs.project = j2.project AND start > now() - interval '1 hour')
            order by priority, account_priority, job_id 
            limit 1) jobs
        LEFT OUTER JOIN company
            ON jobs.company_id = company.id
        , enabled
        WHERE enabled.status IS TRUE
        FOR UPDATE of jobs
    )
    UPDATE jobs
    SET    start = now() 
    FROM   thejob
    WHERE  jobs.job_id = thejob.job_id
    RETURNING json_build_object('job_id', jobs.job_id, 'platform', jobs.platform, 'project', jobs.project, 'firstSeen', thejob.first_seen);

$BODY$;

锁定的目的是确保一次只能由一个工人执行一项工作(这似乎按预期工作),但是调用此函数时偶尔会出现死锁,并且想知道我的显式锁定是否为可能引起问题。

WHERE NOT EXISTS用于确保同一项目不会再次启动,除非它在1小时后超时。

1 个答案:

答案 0 :(得分:0)

由于只涉及一行,因此CTE似乎不必要。仅当您要更新几行并以一定顺序锁定它们以避免死锁时,这才有意义。

由于查询将仅锁定单个jobs行,因此它本身不能死锁任何东西。

同一事务中还有许多其他数据修改语句,这些语句与您显示的语句一起会导致死锁。

请记住,锁将保持到事务结束!