Database 如何更新Google App Engine NDB对象上的数据,使其可以同时进行多次写入

Database 如何更新Google App Engine NDB对象上的数据,使其可以同时进行多次写入,database,python-2.7,google-app-engine,google-cloud-datastore,app-engine-ndb,Database,Python 2.7,Google App Engine,Google Cloud Datastore,App Engine Ndb,情况是这样的 我有一个这样的模特 class Content(ndb.Model): likeCount=ndb.IntegerProperty(default=0) likeUser = ndb.KeyProperty(kind=User, repeated=True) 当生成新内容时,会生成新的“内容”对象,如 content_obj_key = Content(parent=objContentData.key, #Where ContentData is an

情况是这样的 我有一个这样的模特

class Content(ndb.Model):
    likeCount=ndb.IntegerProperty(default=0)
    likeUser  = ndb.KeyProperty(kind=User, repeated=True)
当生成新内容时,会生成新的“内容”对象,如

content_obj_key = Content(parent=objContentData.key, #Where ContentData is     another ndb.Model subclass
                             likeUser=[],
                             likeCount=0
                           ).put()
当任何用户喜欢与下面相同的内容时,函数被调用

def modify_like(contentData_key, user_key):
    like_obj = Content.query(parent=contetData_key).get()
    if like_obj:
        like_obj.likeUser.append(user_key)
        like_obj.likeCount += 1
        like_obj.put()
问题:
现在的问题是,当同时有4个以上的用户喜欢相同的内容时,这个对象会写入错误的数据。
我的意思是说userA、userB、userC和userD同时喜欢这些数据,目前只有userE喜欢相同的内容。
因此,在所有新的四个写之后,“likeCount”不是5,总是小于5,“likeUser”列表长度也小于5

那么我该如何解决这个问题呢?
因此,数据始终保持一致。

可能是某些更新相互影响,因为多个用户可能同时递增相同的计数值

如果userA和userB同时获取内容对象-两者都具有相同的计数值(likeCount=1)。然后两者都增加到值2-当它的总数应为3时

一种可能的解决方案是使用分片。当应用程序中的实体可能有大量写操作时,这非常有用。计数是该实体的所有碎片总数。文档中的示例代码:

NUM_SHARDS = 5

class SimpleCounterShard(ndb.Model):
    """Shards for the counter"""
    count = ndb.IntegerProperty(default=0)

def get_count():
    """Retrieve the value for a given sharded counter.

    Returns:
        Integer; the cumulative count of all sharded counters.
    """
    total = 0
    for counter in SimpleCounterShard.query():
        total += counter.count
    return total

@ndb.transactional
def increment():
    """Increment the value for a given sharded counter."""
    shard_string_index = str(random.randint(0, NUM_SHARDS - 1))
    counter = SimpleCounterShard.get_by_id(shard_string_index)
    if counter is None:
        counter = SimpleCounterShard(id=shard_string_index)
    counter.count += 1
    counter.put()
有关分片计数器的更多信息和示例,请访问: 使用:

事务是一个或一组有保证的操作 是原子的,这意味着事务从来都不是部分的 应用要么应用事务中的所有操作, 或者它们都不适用。事务的最长持续时间为 60秒,30秒后有10秒的空闲到期时间


如果我删除“仅1次写入/秒”的“父级”约束,同样的问题仍然存在。请阅读有关最终一致性的内容。还有许多其他s.o.的问题和文章涉及到这一点。不仅必须考虑到最终的一致性,而且我也看不到任何交易被使用的证据,因此覆盖结果是意料之中的。如果您不需要实时准确度,但确实需要准确的结果,也可以考虑排队和批处理更新。Brent#事务对于原子是有保证的,但是如果两个事务读取相同的值呢?在这种情况下,两者都将完成,但结果将是错误的,正如Jeff和我通过示例说明的那样。因为
modify_like()
中的操作集保证是原子的,所以后面的请求将失败,必须重试。然后它将获得更新的
实体,如_obj
实体。感谢Jeff的回复。我会试试这个,很快会让你知道的。
@ndb.transactional(retries=10)
def modify_like(contentData_key, user_key):
    ...