Objectify条件更新事务模式

时间:2014-12-16 19:27:35

标签: java objectify google-app-engine

给出一个简单的Objectify v5实体,如

@Entity
@Cache
public class Thing {
    @Id
    public String uid;
    public int a;
    public int b;
}

当我希望以下内容成立时,更新现有实体的正确方法是什么

  • 0更新任何内容时的数据库操作。即当没有属性更改时,应该使用缓存而不是无效。
  • 一致性:属性ab的独立,并发更新不得还原其他属性的更改=>交易

如果没有检测到变化,以下内容应该有效

public static Thing updateA( final String uid, final int value ) {

    return ofy().transact(new Work<Thing>() {
        @Override
        public Thing run() {
            Thing thing = ofy().load().type(Thing.class).id(uid).safe();
            thing.a = value;
            ofy().save().entity(thing);
            return thing;
        }
    });
}

然而,由于Objectify--据我所知 - 没有检测到变化,上面的代码实际上会覆盖实体,刷新缓存等等。我正试图阻止它。

如果保存是有条件的,如

if (thing.a != value) {
    thing.a = value;
    ofy().save().entity(thing);
} else {
    // consistency guarantees w/o save?
    // need to transaction rollback / commit?
}

会按预期工作吗?换句话说,只是加载一个值但从不保存一个值的事务会发生什么?我对乐观锁定的理解是,在事务结束时的某些操作需要验证状态是否符合要求。感觉就像没有保存时​​一样。

1 个答案:

答案 0 :(得分:1)

你在这里说了几件相互矛盾的事情,但是让我看看能否为你解决这个问题:

  • 您无法使用0数据库操作安全地更新实体。缓存始终表示陈旧数据。 唯一安全更新数据的方法是在事务中执行数据库读取(如果合适,还有写入)。阅读将花费您1次操作。

  • 事务通过回滚和重试冲突来排序。它们具有连续应用的有效行为。如果您在事务中执行幂等更新,您将永远不会让#34;写入彼此踩踏&#34;问题。这是数据存储行为(冲突错误)和Objectify行为(重试冲突)的组合。

您可能想知道是否可以检查缓存以查看是否可以避免启动真实交易。如果您不关心丢失更新,请不要。当您读取并检查值时,它可能已在数据库中更改。您的更新会丢失,因为它的订购定义不明确。事务为您提供可预测(序列)的更新顺序。

当然还有另一种解决这个问题的方法,就是以某种方式保证你的实体永远不会看到争用。这通常是一个非常棘手的问题,这就是我们进行交易的原因。