1

我正在使用 JDO 访问 Datastore 实体。我目前遇到问题,因为不同的进程并行访问相同的实体,我不确定如何解决这个问题。

我有包含值和计算值的实体:(key,value1,value2,value3,计算)

计算发生在单独的任务队列中。用户可以随时编辑这些值。如果更新了这些值,则会将一个新任务推送到覆盖旧计算值的队列中。

我目前遇到的问题是在以下情况下:

  1. 用户创建实体
  2. 任务开始
  3. 用户在其初始条目中发现错误并快速更新实体
  4. 任务基于旧数据(来自步骤 1)完成并覆盖整个实体,同时删除新输入的值(来自步骤 3)
  5. 用户不高兴

所以我的问题:

  • 我可以在步骤 4 中使任务在更新时失败吗?由于最终的一致性,将任务包装在事务中似乎并不能解决所有情况下的这个问题(或者,很可能,我对数据存储事务的理解是错误的)
  • 使用低级 setProperty 方法是更新实体的单个字段的唯一方法,这会解决我的问题吗?
  • 如果以上都不是,那么处理这样的用例的最佳方法是什么

背景:

目前,我不介意为了一致性而交易表现。我以后会关心性能。

这是我的第一个 AppEngine 应用程序,因为它是一个学习过程,它没有使用一些最佳实践。我很清楚,事后看来,我应该对我的数据模式进行更长时间和更努力的思考。例如,我的所有实体都没有在合适的地方使用祖先关系。我来自关系背景,这表明。

我正在计划进行一次重大的重构,可能会转向 Objectify,但与此同时,我有一些紧迫的问题需要尽快解决。我想首先完全了解数据存储区。

4

3 回答 3

2

显然,JDO 为事务提供了乐观并发检查(如果用户启用它),这将防止/减少此类事情的机会。乐观并发同样适用于关系数据存储,因此您可能知道它的作用。

Google 的 JDO 插件显然使用了低级 API setProperty() 方法。日志甚至会告诉您进行了哪些低级别调用(根据 PUT 和 GET)。迁移到其他一些 API 本身并不能解决此类问题。

于 2012-11-20T10:19:50.667 回答
2

每当您需要在 GAE 中处理写入冲突时,您几乎总是需要事务。然而,它不仅仅是“使用事务”那么简单:

  1. 首先,确保可以在事务中定义每个逻辑工作单元。交易有限制;没有祖先就没有查询,只能访问一定数量的实体组。您可能会发现在事务开始之前需要做一些额外的工作(即,查找将参与事务的实体的键)。
  2. 确保每个工作单元都是幂等的。这很关键。某些工作单元是自动幂等的,例如“将我的电子邮件地址设置为 xyz”。某些工作单元不是自动幂等的,例如“将 5 美元从账户 A 转移到账户 B”。您可以通过在事务开始之前创建实体,然后删除事务内的实体来使事务具有幂等性。在交易开始时检查实体是否存在,如果它被删除,只需返回(完成 txn)。
  3. 当您运行事务时,ConcurrentModificationException在循环中捕获并重试该过程。现在,当任何 txn 发生冲突时,它只会重试直到成功。

这里关于冲突的唯一坏处是它会减慢系统速度并在重试期间浪费精力。但是,您将每秒至少获得一个已完成的事务(如果您有 XG 事务,可能会少一些)吞吐量。

Objectify4 为您处理重试;只需将您的工作单元定义为 run() 方法并使用 ofy().transact() 运行它。只要确保你的工作是幂等的。

于 2012-11-20T17:56:16.577 回答
1

在我看来,您可以阻止第一个任务更新对象,因为某些值从任务首次启动时发生了变化。

或者您可以在任务请求中嵌入对象的值,以便第二个计算任务将恢复具有一致值和计算成员的对象状态。

于 2012-11-20T21:16:02.000 回答