是否以事务方式修改实体数据(视需要而定)

时间:2010-02-13 14:59:14

标签: python google-app-engine transactions

保持代码模块化和解耦但避免两次输入交易的最佳方法是什么?

实体通常具有加载,修改和存储数据的类方法。通常,这必须是事务性的,以与子/兄弟/堂兄实体保持一致。这是模式:

class MyEntity(db.Model):
  # ... some properties

  @classmethod
  def update_count(cls, my_key):
    def txn():
      me = db.get(my_key)
      me.count += 23
      me.put()
      OtherEntity.update_descendants(ancestor=me)
    return db.run_in_transaction(txn)

通常,您应该获取实体,修改它们并将它们存储在一次块中。该技术 更高效;但有时性能不如模块化和可维护性重要。这两个更新应该解耦。 (也许update_descendants经常被隔离调用,它负责存储数据。)

但是,以下代码是一个错误:

class OtherEntity(db.Model):
  # ... some properties

  @classmethod
  def update_descendants(cls, ancestor):
    def txn(): # XXX Bug!
      descendants = cls.all().ancestor(ancestor).fetch(10)
      for descendant in descendants:
        descendant.update_yourself(ancestor.count)
      db.put(descendants)
    return db.run_in_transaction(txn)

这引发了一个例外:

>>> MyEntity.update_count(my_key=some_key_i_have)
Traceback (most recent call last):
  ...
BadRequestError: Nested transactions are not supported.

那么我怎样才能充分利用这两个方面:模块化和正确性?

2 个答案:

答案 0 :(得分:2)

我使用的模式是有一个参数,指示是否需要事务行为。

class OtherEntity(db.Model):
# ... some properties

@classmethod
def update_descendants(cls, ancestor, with_transaction=True):
  if with_transaction:
    return db.run_in_transaction(cls.update_descendants, ancestor,
                                 with_transaction=False)

  # Now I can assume I am in a transaction one way or another...
  descendants = cls.all().ancestor(ancestor).fetch(10)
  for descendant in descendants:
    descendant.update_yourself(ancestor.count)
  return db.put(descendants)

可以扩展相同的原则,以指示是否对put负责,或将其留给来电者。

答案 1 :(得分:1)

我建议将事务函数设置为顶级类方法。然后,您可以根据需要直接或db.run_in_transaction调用它们。