给出一个简单的Objectify v5实体,如
@Entity
@Cache
public class Thing {
@Id
public String uid;
public int a;
public int b;
}
当我希望以下内容成立时,更新现有实体的正确方法是什么
a
和b
的独立,并发更新不得还原其他属性的更改=>交易如果没有检测到变化,以下内容应该有效
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?
}
会按预期工作吗?换句话说,只是加载一个值但从不保存一个值的事务会发生什么?我对乐观锁定的理解是,在事务结束时的某些操作需要验证状态是否符合要求。感觉就像没有保存时一样。
答案 0 :(得分:1)
你在这里说了几件相互矛盾的事情,但是让我看看能否为你解决这个问题:
您无法使用0数据库操作安全地更新实体。缓存始终表示陈旧数据。 唯一安全更新数据的方法是在事务中执行数据库读取(如果合适,还有写入)。阅读将花费您1次操作。
事务通过回滚和重试冲突来排序。它们具有连续应用的有效行为。如果您在事务中执行幂等更新,您将永远不会让#34;写入彼此踩踏&#34;问题。这是数据存储行为(冲突错误)和Objectify行为(重试冲突)的组合。
您可能想知道是否可以检查缓存以查看是否可以避免启动真实交易。如果您不关心丢失更新,请不要。当您读取并检查值时,它可能已在数据库中更改。您的更新会丢失,因为它的订购定义不明确。事务为您提供可预测(序列)的更新顺序。
当然还有另一种解决这个问题的方法,就是以某种方式保证你的实体永远不会看到争用。这通常是一个非常棘手的问题,这就是我们进行交易的原因。