支援交易運算
在許多資料庫運算中,為了保持相關的資料庫運算結果能夠不被分割地將同時送進資料庫(也就是一旦有一個操作發生失敗,則整串操作都會同時取消),所以提供了「交易」(transaction)的運算。
Google App Engine 上的 datastore 當然也支援「交易」運算,在上述的例子中,共有兩個資料庫運算--
Product
entity 的寫入以及 Counter
entity 的更新,試著想像這兩個操作若各自(或同時)發生錯誤時會有什麼問題,若是 Product
entity 在寫入時發生錯誤,程式就中斷了,那就沒什麼太大的問題,若是 Product
entity 成功寫入 datastore,但 Counter
entity 在更新時發生錯誤,這時就會造成計數器的統計數量不一致,這時候就適合使用交易運算了。交易運算的限制
在 Google App Engine 中,交易運算只能操作相同 entity group 的資料,如果我們要將
Product
及 Counter
的新增動作在同一個交易運算中完成的話,就必須讓它們成為同一個 entity group。要成為同一個 entity group,不管是
Product
還是 Counter
都需要一個共同的 parent,因此需要一個額外的 data model 來作為這個 entity group 的 root,這裡我提供一個 Index
的 model,順便用來作為每一筆 Product
資料的「序號產生器」 :pclass Index(db.Model):
max_index = db.IntegerProperty(required=True, default=0)
有了這個 model 後,新增
Product
及更新 Counter
的動作就可以改寫為:# 新增 product 的程式片段...
...
# 從 Index 中取出 Product 的 index
ind = Index.get_by_key_name('product')
if ind is None:
ind = Index()
ind.max_index += 1
ind.put()
# 新增 product entity 並設定 parent 為 ind
p = Product(parent=ind, key_name="product_%d" % ind.max_index,........)
p.put()
# 根據 key_name 取得 counter,並且指定 parent
counter = Counter.get_by_key_name('product_counter', parent=ind.key())
if counter is None:
# 如果 counter 不存在,則建立一個新的,別忘了指定 key_name 及 parent
counter = Counter(parent=ind, key_name='product_counter')
counter.count += 1
counter.put()
在新增
Product
及 Counter
時,都加上指定 parent
的參數,以此將這些資料建構成一個 entity group,然而,一旦資料在 entity group 中,在取出時也要加上 parent
參數。作成交易運算的函式
因此,我們可以把上面的程式碼包成一個函式,比方說是
create_product
,這樣就可以利用 Datastore API 中的 run_in_transaction
函式來作成交易運算了。....
def create_product():
# 放入上述的程式碼
....
# 新增資料時...
from google.appengine.ext import db
db.run_in_transaction(create_product)
如此一來,只有當
Index
, Product
及 Counter
的資料操作都成功時,更新的資料才會進入 datastore 中。
沒有留言:
張貼留言