简体   繁体   English

客观化条件更新交易模式

[英]Objectify conditional update transaction pattern

Given a simple Objectify v5 entity like 给定一个简单的Objectify v5实体,例如

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

What is the correct way of updating existing entities when I want the following to be true 当我希望满足以下条件时,更新现有实体的正确方法是什么?

  • 0 database operations when the update changes nothing. 更新无任何更改时,数据库操作为0。 Ie the cache should be used and not invalidated when there is no property change. 也就是说,在没有属性更改的情况下,应使用缓存并且不要使缓存无效。
  • consistency: independent, concurrent updates of properties a and b must not revert changes of the other property back => transaction 一致性:属性ab独立,并发更新不得将其他属性的更改还原回=>事务

Without detection of changes, the following should work 在未检测到更改的情况下,以下应该起作用

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;
        }
    });
}

However, since Objectify - to my knowledge - does not detect changes, above code would actually overwrite the entity, flush the cache, etc. Exactly what I try to prevent. 但是,由于-据我所知-Objectify无法检测到更改,因此上述代码实际上将覆盖实体,刷新缓存等。正是我试图防止的事情。

If saving is made conditional like 如果保存是有条件的

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

would that work as desired? 会按预期工作吗? In other words, what happens with a transaction that just loads a value but never saves one? 换句话说,只加载一个值却从未保存一个值的事务会发生什么? My understanding of optimistic locking is that some action at the end of an transaction needs to verify that the state is as desired. 我对乐观锁定的理解是,事务结束时需要采取一些措施来验证状态是否符合要求。 That feels like it's missing when not saving. 感觉好像不保存时就丢失了。

You've said a couple conflicting things here, but let me see if I can sort this out for you: 您在这里说了几句矛盾的话,但让我看看是否可以为您解决:

  • You cannot update entities safely with 0 database operations. 您无法使用0个数据库操作安全地更新实体。 The cache always represents stale data. 缓存始终代表过时的数据。 The only safe way to update data is by performing a database read (and, if appropriate, a write) in a transaction. 唯一安全的数据更新方法是在事务中执行数据库读取(如果合适,还可以进行写入)。 A read will cost you 1 operation. 读取将花费您1次操作。

  • Transactions sort themselves out by rolling back and retrying conflicts. 事务通过回滚并重试冲突来解决自身问题。 They have the effective behavior of being applied serially. 它们具有被串行应用的有效行为。 If you perform idempotent updates in a transaction, you will never have the "writes stepping on each other" problem. 如果您在事务中执行幂等更新,那么您将永远不会遇到“彼此踩写”的问题。 This is a combination of datastore behavior (error on conflict) and Objectify behavior (retrying on conflict). 这是数据存储行为(发生冲突错误)和对象化行为(发生冲突重试)的组合。

You may wonder if you can check the cache to see if you can avoid starting a real transaction. 您可能想知道是否可以检查缓存以查看是否可以避免启动实际事务。 Not if you care about losing updates. 如果您担心丢失更新,则不会。 By the time you read and check a value, it may have already changed in the database. 在您阅读和检查值时,该值可能已在数据库中更改。 Your update is lost because it has a poorly-defined ordering. 您的更新丢失,因为它的顺序定义不正确。 Transactions give you predictable (serial) order of updates. 事务为您提供了可预测的(串行)更新顺序。

Of course there's another way of solving this problem, which is to somehow guarantee that your entity never sees contention. 当然,还有另一种解决此问题的方法,即以某种方式保证您的实体永远不会出现争用。 That's often a very hard problem, which is why we have transactions. 这通常是一个非常棘手的问题,这就是我们进行交易的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM