【问题标题】:GAE: Prevent inadvertent overwriting of dataGAE:防止无意覆盖数据
【发布时间】:2015-07-05 12:55:34
【问题描述】:

假设我有一个具有两个属性的人的实体:

class Person(ndb.Model)
    payments = ndb.IntegerProperty(default=0)
    name = ndb.StringProperty()

我在想我会在事务中更新payments,但在更新name 时我不需要事务。

但是,在以下情况下,我可能会失去payments 的值:

时间 |实例1 | INSTANCE2(交易中) ==================================================== === || | person1 = key1.get() | || | person1.name = "约翰" | person1 = key1.get() || | [其他的东西] | person1.payments = 100 || | [需要一些时间] | person1.put() || |人1.put() | || | \/

在这种情况下,似乎 INSTANCE1 会覆盖 INSTANCE2 中写入的付款金额,并且付款金额会丢失。

这是否意味着我在更新name时也需要使用事务来确保重要数据永不丢失?

或者更一般地说,如果我使用事务来更新实体的任何属性,我应该使用事务来更新该实体的所有内容吗?

【问题讨论】:

    标签: google-app-engine transactions google-cloud-datastore app-engine-ndb


    【解决方案1】:

    事务仅在 .put() 调用期间起作用...因此,无论您是否使用事务,您的示例在两种情况下都会产生相同的效果。您将需要实现自己的锁定机制来识别对象自加载后是否已更改...就像检查 last_updated DateTimeProperty ...然后引发异常 (https://en.m.wikipedia.org/wiki/Optimistic_concurrency_control)

    (对不起,格式平淡...我在移动浏览器上)

    【讨论】:

    • oops...我最初误读了这个...对于保存在事务之外的单个实体,那么您必须实现自己的乐观并发...。但是如果您要包装一个事务中的一堆工作,那么我上面所说的并不是真正需要的,因为乐观锁定将由数据存储区和实体组为您完成
    【解决方案2】:

    是的,在这种情况下,您将丢失 payments 的新值。数据存储区没有更新属性值的概念,实体总是被完全覆盖。

    Datastore API 不区分创建新实体和更新现有实体。如果对象的键表示已存在的实体,则 put() 方法将覆盖现有实体。

    当两者都是事务时,它工作正常。这正是它的表现。

    当事务开始时,App Engine 通过检查事务中使用的实体组的最后更新时间来使用乐观并发控制。为实体组提交事务后,App Engine 会再次检查事务中使用的实体组的上次更新时间。如果它在我们的初始检查后发生了变化,则会引发异常。

    在这种特殊情况下,当实例 A 中的事务提交时,App Engine 会注意到该实体在事务开始后已在其他地方更新。事务A 被取消,默认重试。

    【讨论】:

      【解决方案3】:

      是的,对所有更新都使用事务以避免您描述的情况可能是最安全的。您唯一的选择(我能想到的)是使用@Nick Franceschina 建议的锁定机制。

      【讨论】:

        猜你喜欢
        • 2011-12-15
        • 2019-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-29
        • 1970-01-01
        • 1970-01-01
        • 2018-06-27
        相关资源
        最近更新 更多