sql – Postgres并发和可序列化.我需要一个SERIALIZABLE隔离级别吗?

我有一个项目和工作表:

项目

> id = PK
> job_id =作业FK
> status = IN_PROGRESS |完成

工作

> id = PK

项目开始为IN_PROGRESS,但是对它们进行工作,并交给工作人员进行更新.我有一个更新程序,正在更新项目,因为它们进来,具有新的状态.我一直在做的这个方法是(伪代码):

def work(item: Item) = {
  insideTransaction {
    updateItemWithNewStatus(item)
    jobs,items = getParentJobAndAllItems(item)
    newJobStatus = computeParentJobStatus(jobs,items)
    // do some stuff depending on newJobStatus
  }
}

那有意义吗?我希望这在一个并发环境中工作.我现在的问题是,COMPLETE是多次到达一个工作,当我只想在COMPLETE上做逻辑一次.

如果我将事务级别更改为SERIALIZABLE,那么我会得到“错误:由于事务之间的读/写依赖关系而无法序列化访问”错误.

所以我的问题是:

>我需要SERIALIZABLE吗?
>我可以用SELECT FOR UPDATE和哪里取消?
有人向我解释发生了什么,为什么?

编辑:我已经重新打开了这个问题,因为我对以前的答案解释不满意.有人能为我解释这个吗?具体来说,我想要一些这个伪代码的示例查询.

解决方法

如果希望作业同时运行,则SERIALIZABLE和SELECT FOR UPDATE都不会直接运行.

如果您使用SELECT FOR UPDATE锁定行,那么另一个进程将在执行SELECT FOR UPDATE时直接阻止,直到第一个进程提交事务.

如果您执行SERIALIZABLE,则两个进程都可以同时运行(处理同一行),但是由于数据库会检测到冲突,所以至少有一个进程在执行COMMIT时会失败.如果与数据库中的任何其他查询冲突,同时影响相关行,则SERIALIZABLE也可能会失败.使用SERIALIZABLE的真正原因正是如果您尝试防止其他作业执行的并发数据库更新,而不是阻止相同的作业执行两次.

注意有一些技巧使SELECT FOR UPDATE跳过锁定的行.如果你这样做,那么你可以有实际的并发性.见Select unlocked row in Postgresql.

我更经常看到的另一种方法是将“status”列更改为在处理作业时使用的第3个临时状态.通常情况下,会有“PENDING”,“IN_PROGRESS”,“COMPLETE”等状态.当您的流程搜索工作时,会找到一个“PENDING”作业,立即将其移动到“IN_PROGRESS”并提交交易,然后继续执行该操作,最后将其移动到“完成”.缺点是如果进程在处理作业时死机,它将无限期地保留在“IN_PROGRESS”中.

相关文章

SELECT a.*,b.dp_name,c.pa_name,fm_name=(CASE WHEN a.fm_n...
if not exists(select name from syscolumns where name=&am...
select a.*,pano=a.pa_no,b.pa_name,f.dp_name,e.fw_state_n...
要在 SQL Server 2019 中设置定时自动重启,可以使用 Window...
您收到的错误消息表明数据库 'EastRiver' 的...
首先我需要查询出需要使用SQL Server Profiler跟踪的数据库标...