如果最近的事务引发了"特殊"异常,那么事务性db.get()是否可以返回陈旧的结果?

Alb*_*ert 6 google-app-engine google-cloud-datastore

这是在appengine 交易文档 ...

注意:如果您的应用程序在提交事务时收到异常,则并不总是意味着事务失败.在已提交事务并最终成功应用事务的情况下,您可以收到Timeout,TransactionFailedError或InternalError异常...

请考虑以下情形

  1. A在事务中更新实体.
  2. 事务操作导致上述特殊的"异常",其中事务已经提交并最终将被应用
  3. db.get(entity_a_key_goes_here)在第2步之后或几乎与第2步同时在另一笔交易中运行.
  4. 如果上述步骤返回3 None,我通过键设置为创建该实体entity_a_key_goes_heredb.put()它(步骤3和在同一事务中此步骤的运行).

我的问题:

上面步骤3中的事务 db.get()操作是否有可能返回过时值(或者不是步骤1中设置的更新值)?事务db.get()操作是否保证即使在它之前发生"怪异"事务异常,也会返回最新鲜的结果?

Tor*_*rne 2

get 并不是真正的“事务性”;如果事务仅包含读取,则提交事务实际上不会执行任何操作。在事务中执行读取仅保证一件事:如果在应用事务中的任何写入时读取返回的值不再是最新值,则事务将中止并且不会发生任何写入。

因此,允许发生以下事件序列:

  1. 开始交易1。
  2. 在事务 1 中,您读取实体 A,它返回状态 A1。
  3. 在事务 1 中,您将实体 A 从状态 A1 更新到状态 A2。
  4. 提交事务 1 时,它失败并出现上述异常之一。
  5. 开始交易2。
  6. 在事务 2 中,您读取实体 A,它返回状态 A1。
  7. 事务 1 在后台应用于数据存储,将 A 从状态 A1 更改为状态 A2。
  8. 结束事务 2(没有提交,因为没有写入)。

但是,这一系列事件是不同的:

  1. 开始交易1。
  2. 在事务 1 中,您读取实体 A,它返回状态 A1。
  3. 在事务 1 中,您将实体 A 从状态 A1 更新到状态 A2。
  4. 提交事务 1 时,它失败并出现上述异常之一。
  5. 开始交易2。
  6. 在事务 2 中,您读取实体 A,它返回状态 A1。
  7. 在事务 2 中,您将实体 A 从状态 A1 更新到状态 A3。
  8. 事务 1 在后台应用于数据存储,将 A 从状态 A1 更改为状态 A2。
  9. 事务 2 现在不会成功提交,因为它将要应用的写入基于实体 A 的过时版本。它将失败,并且 A 将处于状态 A2。

因此,将步骤 4 添加到问题后,您就处于此处的第二个事件序列中。即使实体确实存在,步骤 3 中的 get 也可能返回 None,但在这种情况下后续写入不可能成功:事务已过期,因此无法提交。该事务将被重试,第二次时,get 将返回步骤 1 中写入的对象,这就是您想要的。

因此,非常简短的答案是:是的,它可以返回过时的值,但可以保证,如果结果是过时的,则同一事务中对该实体的后续写入将失败,因此这实际上不会导致问题。