Google app engine 跨组事务需要显式指定get\u或\u insert异常

Google app engine 跨组事务需要显式指定get\u或\u insert异常,google-app-engine,transactions,Google App Engine,Transactions,我们正在从文件加载电子邮件列表,同时为每个电子邮件地址同时放置大量数据存储实体,并在表单中偶尔出现错误: BadRequestError: cross-group transaction need to be explicitly specified, see TransactionOptions.Builder.withXG 失败的Python方法调用: EmailObj.get_or_insert(key_name=email, source=source, reason=reason)

我们正在从文件加载电子邮件列表,同时为每个电子邮件地址同时放置大量数据存储实体,并在表单中偶尔出现错误:

BadRequestError: cross-group transaction need to be explicitly specified, see TransactionOptions.Builder.withXG
失败的Python方法调用:

EmailObj.get_or_insert(key_name=email, source=source, reason=reason)
其中email是地址字符串,source和reason是StringProperties


问题:get_或_insert调用如何为一个简单的数据存储模型(2个字符串属性)启动事务并获取不同组的实体?我希望上面的方法要么读取与给定键匹配的现有对象,要么存储新实体

注意:我不知道确切的内部实现,这只是一个理论

由于您没有指定父级,因此没有可以“锁定”的实体组/从一开始就建立为交易将限于的

“获取”或“插入”操作通常是检查具有该键名的实体是否存在,如果不存在,则创建一个新实体。如果没有父对象,这个新实体将位于它自己的组中,我们称它为
new\u组

现在,要完成与
get\u或\u insert
自动关联的事务,需要进行冲突检查。 冲突意味着一个具有相同键名的实体是由一个并发任务创建的(在我们检查该实体是否存在之后,但在我们的事务结束之前),该实体也将有自己的不同组,我们称之为
其他组

只有在冲突是真实的情况下,这种冲突检查才能有效地访问
新组
其他组
,从而导致异常

通过指定父对象,问题就不存在了,因为
new_group
other_group
实际上都是同一个组-父对象的组。
get\u或\u insert
事务将仅限于此组

我认为,即使在生产中,这个理论也可以得到验证(如果理论是正确的,那么错误实际上是无害的——地址毕竟是重复的)

第一步是确认发生的事件与在极短时间内同时插入两次的相同的电子邮件地址有关

包装在try/exception中并记录相应的电子邮件地址,然后对照输入文件进行检查-它们应该是重复的,并且我认为它们在文件中彼此非常接近

<>你可以强制这个条件——有意地在每隔5-10个电子邮件中插入重复地址(或者你认为相关的其他速率)。 根据应用程序的实际实现方式,您可以在输入文件中插入重复项,或者,如果使用任务-创建/排队重复任务,或者只需调用两次
get\u或\u insert
(不确定最后一个是否足够有效,因为它可能发生在同一线程/实例上)。最终记录或跟踪注入的重复地址

异常的发生率现在应该增加,可能与强制重复插入率成比例。大多数(如果不是所有的话)对应的记录地址应该与被注入的跟踪副本相匹配

如果你得到了那么多的重复条目作为触发器被确认。剩下要确认的是同一电子邮件地址的不同实体组-我想不出确切的方法来检查,但我也想不出与重复电子邮件地址相关的其他组


总之,只要在
get\u或\u insert
calls'中添加
xg=True
,如果我的理论是正确的,错误应该消失:)

你看到了吗?是的,我已经查看了围绕此错误的问题。答案主要是关于缺少父参数的手工操作,但是我还没有看到一个明确的答案来解释哪些组参与了这个特定的事务。这个错误似乎暗示至少有2个实体试图被修改。谢谢,听起来似乎有道理。今天早些时候,有人建议可能get\u或\u insert已加入现有事务,但我裁定,我们的延迟是通过在get\u或\u insert调用周围使用try/except并记录db.is\u in\u transaction(),该函数在所有情况下都返回false,因此看起来可以确定唯一正在进行的事务是get\u或\u insert down。这只剩下两个实体(人们可能会认为),XG的使用解决了这个问题(必须将get_或_insert函数复制到通过XG=True标志的get_或_insert_xp版本)。我想我们只能生活在不知道在这种情况下到底发生了什么的情况下。