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):
...