Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.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
长期运行的django事务完整性错误_Django_Postgresql_Transactions - Fatal编程技术网

长期运行的django事务完整性错误

长期运行的django事务完整性错误,django,postgresql,transactions,Django,Postgresql,Transactions,在使用Django时,我们应该如何避免长时间运行的事务“完整性错误”?(尤其是外键完整性错误) 我们的应用程序有实体“A”和“B”(为了简单起见) 它有以下语义 “B”有一个指向“a”的外键字段。 当事件发生时,会定期创建多个“B”(以千分之一百计)。 创建多个“B”应始终是事务性的,因为我们应始终构建所有“B”或什么都不构建,以便在出现错误时,我们可以重新触发事件。 有时,一些“A”可能会被破坏。换句话说,我们无法控制“A”的生命周期 我目前正在使用django的基本事务功能(transact

在使用Django时,我们应该如何避免长时间运行的事务“完整性错误”?(尤其是外键完整性错误)

我们的应用程序有实体“A”和“B”(为了简单起见) 它有以下语义

“B”有一个指向“a”的外键字段。 当事件发生时,会定期创建多个“B”(以千分之一百计)。 创建多个“B”应始终是事务性的,因为我们应始终构建所有“B”或什么都不构建,以便在出现错误时,我们可以重新触发事件。
有时,一些“A”可能会被破坏。换句话说,我们无法控制“A”的生命周期

我目前正在使用django的基本事务功能(transaction.atomic)来确保“B”的原子创造行为

由于生成“B”需要一些时间(1小时左右),如果同时删除了某些“已引用的”“A”,则整个事务将失败,并出现ForeignKey完整性错误

为了清楚起见,请允许我用简略的图表解释一下

按顺序创建Bi之后

[B1(参考文献A1)、B2(参考文献A2)…Bn(参考文献An)]仅在创建所有B1…Bn时才尝试处理整个操作

创建Bm时(1 如果同时删除了某些“已引用的”“A”,则整个事务将失败,并出现ForeignKey完整性错误

您需要防止这种情况发生。最好的方法是在开始工作之前对“A”对象进行适当的锁定

我建议,在构建“B”的事务中,您首先
从“A”中选择1,其中…FOR SHARE
,或者使用任何Django级别的抽象,该抽象对要引用的行执行相同的底层
SELECT…FOR SHARE

为更新选择…
也可以,它只需要一个您不需要的更强的锁

Django可能称之为“显式”或“悲观”锁定(谷歌)。是的:

它似乎不支持共享,但我想这是你在使用ORM时必须面对的限制。只有当多方面的事情需要防止相同的“a”时,这才是一个问题对象同时被删除,因为对于共享
它们可以同时进行,而对于更新
它们必须依次等待

--

在您的评论澄清之后:听起来您真正想要的是,它只锁定引用值的主键,因此您仍然可以更改其他列。当然,您必须使用本机SQL来完成这一操作,并且它是SQL标准的特定于PostgreSQL的扩展,用于共享
和更新
de>

由于生成“B”需要一些时间(1小时左右),如果同时删除了一些“已引用的”A”,则整个事务将失败,并出现ForeignKey完整性错误。 使用signal怎么样?您需要一些东西来检查B的事务是否正在进行。如果是这种情况,请在信号中引发错误,如果不是,请删除A对象

附言:我不知道这是否有效,这只是我在思考这个问题时想到的一个想法。希望它会成功

编辑:进一步解释

class B(models.Model): transaction_active = False def mylongtransactionview(request): models.B.transaction_active = True go_long_transaction() models.B.transaction_active = False def mypre_delete_A_signal(): if models.B.transaction_active: raise Exception else: pass B类(型号.型号): 事务_活动=错误 def mylongtransactionview(请求): models.B.transaction\u active=True go_long_事务() models.B.transaction\u active=False def mypre_delete_A_信号(): 如果models.B.transaction\u处于活动状态: 引发异常 其他: 通过
感谢您提供的信息。正如您所说,如果应用了表级锁定,构建“B”将始终成功。但问题是,它还阻止访问和修改“A”。对于记录,“A”是表示用户的模型,因此不应通过构建“B”的操作阻止新用户插入和用户信息更新。我的错是没有具体说明具体要求,我的错。顺便说一句,谢谢你的深思熟虑的评论。我只知道“更新”条款,而不知道“共享”子句。如果没有更好的答案,我将确保接受您的答案!
FOR UPDATE
FOR SHARE
是行级锁定,而不是表级锁定。根据提供的附加说明,听起来您真正想要的是PostgreSQL 9.3中为密钥共享添加的一项功能,
,它只锁定引用的值,因此您仍然可以更改其他列。当然,您必须使用本机SQL来执行此操作。哎呀!感谢您提供了正确的更正。是的,您说的对,更新的
和共享的
都是行级别的。但是,由于“B”的数量创建的s相当大,行级锁定不足以解决此问题。我肯定会研究密钥共享的
,以前从未听说过(不幸的是,我使用的是postgre 9.2.4)再次感谢您。如果您无法锁定记录,也无法对其进行外部生命周期管理,那么如果它们在工作时消失,您必须重试。您说过这是一个问题。您的其他选项包括:删除外键关系;在“a”仍然存在的情况下单独插入“B”记录(读取提交隔离)。这似乎是有道理的!是否有任何简单的机制可以作为标记来标记事务的运行,而不会产生太多开销?构建单独的表或使用其他外部数据源来标识生命周期似乎有点可疑。是否有任何方法可以知道是否有任何实时运行的插入传输针对特定表的操作?非常好的建议!谢谢!嗯,首先想到的是,可能B类本身有一个属性,所以,当您的视图触发这个长事务时,您可以设置