Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Postgresql 如果两个进程同时修改两个事务中的数据,并且表上存在唯一约束,会发生什么情况?_Postgresql_Triggers_Transactions_Race Condition_Unique Constraint - Fatal编程技术网

Postgresql 如果两个进程同时修改两个事务中的数据,并且表上存在唯一约束,会发生什么情况?

Postgresql 如果两个进程同时修改两个事务中的数据,并且表上存在唯一约束,会发生什么情况?,postgresql,triggers,transactions,race-condition,unique-constraint,Postgresql,Triggers,Transactions,Race Condition,Unique Constraint,我正在考虑一个生产系统中的竞争条件。数据库是PostgreSQL。应用程序是用Java编写的,但这并不相关 有一个名为“versions”的表,其中包含列“entity_ID”和“version”(以及一些其他字段)。此表包含某个实体的版本 有一个应用程序,用户可以在其中修改这些实体 对实体的每次修改都会为选项卡“versions”(使用触发器)创建一个新版本。此触发器在同一个表“versions”中查找最后一个版本,并插入具有相同实体_ID但版本=(最后一个版本+1)的新行 每4:00在Pos

我正在考虑一个生产系统中的竞争条件。数据库是PostgreSQL。应用程序是用Java编写的,但这并不相关

有一个名为“versions”的表,其中包含列“entity_ID”和“version”(以及一些其他字段)。此表包含某个实体的版本

有一个应用程序,用户可以在其中修改这些实体

对实体的每次修改都会为选项卡“versions”(使用触发器)创建一个新版本。此触发器在同一个表“versions”中查找最后一个版本,并插入具有相同实体_ID但版本=(最后一个版本+1)的新行

每4:00在PostgreSQL中运行一个夜间作业,该作业也会更改这些实体,从而更新表“versions”中的数据。这个过程的目的是在早上(在应用程序的用户开始使用它之前)完成它的工作,但不幸的是,它一直持续到白天。由于此过程在函数中运行,因此它是一个大事务。因此,它所做的更改对应用程序不可见

夜间作业使用以下工作流

  • 设置“失败的计数器”=0
  • 迭代需要修改的实体
  • 对BEGIN中的实体进行修改。。例外情况。。端块
  • 如果出现异常,请增加“失败的\u计数器”。将异常和故障实体记录到日志表中
  • 如果“计数器失败”>10,则取消工作
  • 结束工作
这导致以下竞争条件发生了几次(假设X是实体a的最后一个版本):

  • 夜间工作开始
  • 夜间作业修改实体A,创建版本X+1
  • 应用程序还用于修改实体A,同时创建版本X+1(因为夜间作业事务尚未提交,所以版本X+1对应用程序不可见)
  • 夜间作业结束,导致提交
  • 现在有两个版本的版本号为X+1,这会导致应用程序中断
  • 我认为我可以通过使用字段上的唯一约束(entity_ID,version)来解决这个问题。我认为这会导致应用程序在竞争条件步骤3中收到错误(由于违反了唯一约束)。但我不确定在这种情况下,独特的约束是如何工作的。在竞争条件步骤3中,当应用程序添加版本时,数据库是否检查唯一约束?我想不会,因为夜间进程的事务尚未完成。如果我是正确的,并且唯一约束仅在竞争条件步骤4检查,当提交时,那么这会导致整个夜间过程失败,这不是期望的结果

    因此,问题如下

    • 何时检查唯一约束:在竞态条件步骤3或竞态条件步骤4
    • 如果最后一个问题的答案是“竞赛条件4”,那么我如何更改系统的设计以避免上述问题
    默认情况下,PostgreSQL中的唯一约束将在每条语句的末尾进行检查。使用psql测试行为很容易

    一些大的红旗

    由于此过程在函数中运行,因此它是一个大事务

    这不是一个大的事务,因为您正在运行一个函数。这是一个很大的事务,因为您没有在较小的数据子集上多次运行该函数。是否可以在子集上运行函数取决于应用程序

    迭代需要修改的实体

    SQL数据库的粗略经验法则:迭代总是一个错误

    SQL是一种面向集合的语言。处理集合通常比迭代要快,而且通常要快几个数量级

    如果“计数器失败”>10,则取消工作

    这看起来可疑。为什么九次失败都可以?为什么失败是可以的

    我认为我可以通过使用字段上的唯一约束(entity_ID,version)来解决这个问题

    在这两列上还没有唯一的约束,这是一个巨大的、挥舞着的红旗。首先解决这个问题

    应用程序显然应该等待批处理作业完成,但没有等待,这可能是系统设计问题,也可能不是。(这听起来像是一个系统设计问题。)

    每4:00在PostgreSQL中运行一个夜间作业

    你想过3点出发吗

    对此进行测试,但不要在生产服务器上进行测试

    • 扣动扳机
    • 添加带有时区的
      时间戳类型的列
    • 设置该列的默认值。大多数应用程序将使用
      current\u timestamp
      ,但您可能需要
      clock\u timestamp()
    • 在{entity_id,new timestamp column}上添加唯一约束

    取消触发器可能会使您的速度大大加快。

    我认为您永远不会违反约束。(2) 作业修改一个锁定记录的。(3) 应用程序尝试修改,但无法获取锁,因此等待。(4) 作业提交,锁被释放。(5) 应用程序获取锁,进行更新,并创建版本X+2。对不起,我在问题中过度简化了情况。但我测试并发现,步骤(3)使应用程序在且仅在违反唯一约束的情况下等待锁定。所以你在这方面是正确的。你提出了好几点。将功能作为较小的部件运行是一种选择;然而,我认为我更愿意避免对系统进行这样的重写。用集合代替迭代也是一个很好的建议;但是,由于函数执行的操作的复杂性,这是不可行的(我简化了询问的情况)