我正在使用App Engine数据存储,并希望确保行ID的行为类似于MySQL数据库中的“自动递增”字段。
尝试了几种生成策略,但好像无法控制发生的情况:
尝试了几种生成策略,但好像无法控制发生的情况:
- ID不是连续的,似乎有几个“流”并行增长。
- 旧行被删除后,ID会“回收利用”。
我们想删除旧物品(例如两个月前的)
这里有一个模型,它自动跟踪其创建和修改时间。只需使用auto_now_add
和auto_now
参数即可轻松实现。
from google.appengine.ext import db
class Document(db.Model):
user = db.UserProperty(required=True)
title = db.StringProperty(default="Untitled")
content = db.TextProperty(default=DEFAULT_DOC)
created = db.DateTimeProperty(auto_now_add=True)
modified = db.DateTimeProperty(auto_now=True)
db.Query(Document).order("modified")
# or
db.Query(Document).order("created")
我认为这可能是一个相当不错的解决方案,但请注意我没有进行任何测试。语法甚至可能是不正确的!
原则是使用memcache生成单调序列,使用数据存储作为备用方案,以防memcache失败。
class IndexEndPoint(db.Model):
index = db.IntegerProperty (indexed = False, default = 0)
def find_next_index (cls):
""" finds the next free index for an entity type """
name = 'seqindex-%s' % ( cls.kind() )
def _from_ds ():
"""A very naive way to find the next free key.
We just take the last known end point and loop untill its free.
"""
tmp_index = IndexEndPoint.get_or_insert (name).index
index = None
while index is None:
key = db.key.from_path (cls.kind(), tmp_index))
free = db.get(key) is None
if free:
index = tmp_index
tmp_index += 1
return index
index = None
while index is None:
index = memcache.incr (index_name)
if index is None: # Our index might have been evicted
index = _from_ds ()
if memcache.add (index_name, index): # if false someone beat us to it
index = None
# ToDo:
# Use a named task to update IndexEndPoint so if the memcache index gets evicted
# we don't have too many items to cycle over to find the end point again.
return index
def make_new (cls):
""" Makes a new entity with an incrementing ID """
result = None
while result is None:
index = find_next_index (cls)
def txn ():
"""Makes a new entity if index is free.
This should only fail if we had a memcache miss
(does not have to be on this instance).
"""
key = db.key.from_path (cls.kind(), index)
if db.get (key) is not None:
return
result = cls (key)
result.put()
return result
result = db.run_in_transaction (txn)