App Engine数据存储区中的自动增量ID

时间:2011-12-05 23:52:25

标签: google-app-engine google-cloud-datastore auto-increment

我正在使用App Engine数据存储区,并且希望确保行ID与mySQL DB中的“自动增量”字段的行为类似。

尝试了几种策略,但似乎无法控制发生的事情:

  • ID不是连续的,似乎有几个“流”并行增长。
  • 删除旧行后,ids变为“回收”

这样的事情可能吗? 我真的想避免为每一行保留(索引)时间戳。

3 个答案:

答案 0 :(得分:1)

我所知道的是,Google App Engine中可以使用自动生成的ID作为长整数,但不能保证该值正在增加,并且也无法保证这些数字是实际的一个增量。

因此,如果您需要时间戳和增量,请添加一个DateTime字段,但是您不知道这些数字是唯一的。

所以,最好的(我们正在使用的)是:(对不起,但这确实是恕我直言的最佳选择)

  • 使用自动生成的ID作为Long(我们在Java中使用Objectify)
  • 在每个实体上使用时间戳并使用索引查询实体(使用降序索引)以获得前X

答案 1 :(得分:1)

听起来像can't rely on IDs being sequential没有相当多的额外工作。但是,有一种简单的方法可以实现您的目标:

  

我们想要删除旧项目(超过两个月的价值,因为   例如)

这是一个自动跟踪其创建和修改时间的模型。只需使用auto_now_addauto_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)

然后,您可以使用cron jobstask queue来安排删除旧内容的维护任务。找到最旧的东西就像按创建日期或修改日期排序一样简单:

db.Query(Document).order("modified")
# or
db.Query(Document).order("created")

答案 2 :(得分:0)

我认为这可能是一个相当不错的解决方案,但要注意我没有以任何方式,形状或形式测试。语法甚至可能不正确!

原则是使用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)