2012-11-20 61 views
1

我正在使用JDO訪問數據存儲實體。我目前遇到問題,因爲不同的進程並行訪問相同的實體,我不確定如何解決這個問題。對不同實體屬性的並行更新

我有一個包含值的實體和計算值:(鍵,值1,值2,值3,計算值)

計算髮生在一個單獨的任務隊列。 用戶可以隨時編輯這些值。 如果更新值,則會將新任務推送到覆蓋舊計算值的隊列中。

我現在的問題是在以下情形:

  1. 用戶創建
  2. 任務開始
  3. 用戶在他最初進入注意到一個錯誤實體並迅速更新實體
  4. 任務基於舊的數據(來自步驟1)完成並會覆蓋整個實體,也移除所述新輸入的值(來自步驟3)
  5. 用戶不愉快

所以我的問題:

  • 我可以使任務失敗的更新步驟4中?包裹在一個事務中的任務似乎並沒有解決這個問題的,由於最終一致性所有的情況下(或者,很可能,我的數據存儲區事務的理解是錯誤的)
  • 使用低級別的setProperty方法的唯一途徑更新實體的單個字段並解決我的問題嗎?
  • 如果以上都不是,什麼是最好的方式來處理一個用例這樣

背景:

此刻,我不介意的一致性交易業績。以後我會關心表現。

這是我第一次AppEngine應用程式,因爲它是一個學習的過程,它不使用一些最佳實踐。我很清楚,事後看來,我應該更長時間思考我的數據模式。例如,我的實體沒有一個在適當的地方使用祖先關係。我來自關係背景,它顯示。

我籌劃重大重構,可能轉移到客體,但在此期間我也需要被儘快解決的幾個亟待解決的問題。我想先充分了解數據存儲。

回答

2

顯然JDO帶有樂觀併發檢查(如果用戶啓用它)進行交易,這樣可以防止/減少這種事情的機會。樂觀併發性同樣適用於關係數據存儲,因此您可能知道它的功能。

谷歌的JDO插件使用低級API的setProperty()方法效果顯着。日誌甚至會告訴你什麼是低級調用(就PUT和GET而言)。轉向其他一些API本身並不能解決這些問題。

+0

感謝這些指針,我顯然應該對JDO的功能進行一些更好的研究。我已經找到了JDO的樂觀併發功能的一個很好的介紹,但在如何打開正確的日誌語句方面卻很少。你知道,在你的頭頂,是什麼樣的日誌啓用? – Peter

+0

在http://www.datanucleus.org/products/accessplatform_3_1/logging.html和類別「DataNucleus.Datastore.Native」中定義的日誌可能具有大多數本地調用IIRC。樂觀的是在http://www.datanucleus.org/products/accessplatform_3_1/jdo/transactions.html#optimistic – DataNucleus

2

每當你需要處理寫GAE衝突,你幾乎總是需要交易。但是,它不只是簡單的「使用事務」:

所有的
  1. 首先,確保工作的每個邏輯單元可以在事務中定義。交易有限制;沒有祖先的查詢,只能訪問一定數量的實體組。您可能會發現在交易開始之前您需要做一些額外的工作(即參與交易的實體的查找鍵)。
  2. 確保每個工作單元是冪等。這很關鍵。某些工作單元自動爲冪等,例如「將我的電子郵件地址設置爲xyz」。某些工作單位不是自動冪等的,例如「從帳戶A向帳戶B移動$ 5」。您可以通過在交易開始前之前創建實體來使交易冪等,然後刪除交易內的實體。在交易開始時檢查實體是否存在,如果它已被刪除,則簡單地返回(完成txn)。
  3. 當你運行一個事務,抓ConcurrentModificationException和環型重試過程。現在當任何txn發生衝突時,它只會重試直到成功。

這裏發生的碰撞唯一不好的地方是它會降低系統速度並在重試時浪費精力。但是,每秒至少會得到一個完成的事務(如果您擁有XG事務,則可能會少一點)吞吐量。

Objectify4爲您處理重試;只需將您的工作單元定義爲run()方法,並使用ofy()。transact()運行它。只要確保你的工作是冪等的。

+0

明確的答案,特別是在冪等性。太糟糕了,我只能將一個答案標記爲「答案」。 – Peter

+0

Just FYI - 與JDO一樣,除非您自己重試事務,否則您將碰到面向用戶的ConcurrentModificationException。 – stickfigure

1

我看到它的方式,您可以防止第一任務,從因爲某些值已經從當任務被首次推出改變了更新的對象。

或者您可以在嵌入任務請求中的對象的值,使第2計算任務將與一致的價值和calcuated成員恢復對象的狀態。