【问题标题】:Objectify conditional update transaction pattern对象化条件更新事务模式
【发布时间】:2015-02-15 05:21:08
【问题描述】:

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

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

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

  • 0 数据库操作时更新没有改变。 IE。当没有属性更改时,应该使用缓存并且不会失效。
  • 一致性:属性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?
}

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

【问题讨论】:

    标签: java objectify google-app-engine


    【解决方案1】:

    您在这里说了一些相互矛盾的事情,但让我看看是否可以为您解决这个问题:

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

    • 事务通过回滚和重试冲突自行排序。它们具有连续应用的有效行为。如果您在事务中执行幂等更新,您将永远不会遇到“写相互踩踏”的问题。这是数据存储行为(冲突时出错)和 Objectify 行为(冲突时重试)的组合。

    您可能想知道是否可以检查缓存以查看是否可以避免启动真正的事务。如果您关心丢失更新,则不会。当您读取并检查一个值时,它可能已经在数据库中发生了变化。您的更新丢失,因为它的顺序定义不明确。事务为您提供可预测的(串行)更新顺序。

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

    【讨论】:

    • 所以pastebin.com/1DuD19QD 实际上会执行 1 次读取,因为它在事务中,但不保存()是安全的吗?
    • 更正[愚蠢的额外字符,因此评论将发布,忽略]
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-25
    • 1970-01-01
    相关资源
    最近更新 更多