2014-03-26 53 views
1

當調用此POST方法時,我們仍然有重複條目的情況。 我曾詢問過有關堆棧溢出的建議,並給出solution,即利用parent/child方法來保留強烈一致的查詢。複製高複製數據存儲中的條目

我已將所有數據遷移到該表單,並讓它再運行3個月。 但是問題從未解決。

問題是在這裏與這個條件if recordsdb.count() == 1: 它應該是爲了更新條目,而是HRD可能不會總是找到最新的條目,並創建一個新的條目。

正如你所看到的,我們正在編寫/通過父/子方法從記錄閱讀推薦:

new_record = FeelTrackerRecord(parent=user.key,...) 

,但仍然進行檢索時,HRD仍然並不總是獲取最新的條目:

recordsdb = FeelTrackerRecord.query(ancestor = user.key).filter(FeelTrackerRecord.record_date == ...) 

因此,我們很困擾這一點,不知道如何解決它。

@requires_auth 
    def post(self, ios_sync_timestamp): 
     user = User.query(User.email == request.authorization.username).fetch(1)[0] 
     if user: 
      json_records = request.json['records'] 
      for json_record in json_records: 
       recordsdb = FeelTrackerRecord.query(ancestor = user.key).filter(FeelTrackerRecord.record_date == date_parser.parse(json_record['record_date'])) 
       if recordsdb.count() == 1: 
        rec = recordsdb.fetch(1)[0] 
        if 'timestamp' in json_record: 
         if rec.timestamp < json_record['timestamp']: 
          rec.rating = json_record['rating'] 
          rec.notes = json_record['notes'] 
          rec.timestamp = json_record['timestamp'] 
          rec.is_deleted = json_record['is_deleted'] 
          rec.put() 
       elif recordsdb.count() == 0: 
        new_record = FeelTrackerRecord(parent=user.key, 
             user=user.key, 
             record_date = date_parser.parse(json_record['record_date']), 
             rating = json_record['rating'], 
             notes = json_record['notes'], 
             timestamp = json_record['timestamp']) 
        new_record.put() 
       else: 
        raise Exception('Got more than two records for the same record date - among REST post') 
      user.last_sync_timestamp = create_timestamp(datetime.datetime.today()) 
      user.put() 
      return '', 201 
     else: 
      return '', 401 

可能的解決方案:

的最後想法我就必須解決這個問題將是,辭去父/子策略路程,使用user.key PLUS date-string作爲關鍵的一部分。

保存:

new_record = FeelTrackerRecord(id=str(user.key) + json_record['record_date'], ...) 
new_record.put() 

加載:

key = ndb.Key(FeelTrackerRecord, str(user.key) + json_record['record_date']) 
record = key.get(); 

現在我可以檢查是否記錄是無,我將創建一個新條目,否則我將更新它。希望HRD沒有理由不再找到記錄。 您認爲什麼,這是一個有保證的解決方案?

回答

2

可能的解決方案似乎與原始代碼具有相同的問題。想象一下,如果兩臺服務器幾乎同時執行相同的指令,競爭條件。由於Google的過度配置,這一定會偶爾發生。

一個更強大的解決方案應該使用Transactions並在併發導致一致性違規時回滾。用戶實體應該是其自己的實體組的母公司。在事務內的用戶實體中增加記錄計數器字段。只有在事務成功完成時才創建新的FeelTrackerRecord。因此,FeelTrackerRecord實體必須有一個用戶作爲父項。

編輯:在你的代碼的情況下,下面的線將用戶之前去= User.query(...:

Transaction txn = datastore.beginTransaction(); 
try { 

和用戶後,以下行會去。put():

txn.commit(); 
} finally { 
    if (txn.isActive()) { 
     txn.rollback(); 
    } 
} 

這可能會忽略一些流控制嵌套細節,這是這個答案試圖描述的概念。

對於活動事務,如果多個進程(例如多個服務器因爲過度配置而同時執行相同的POST),第一個進程將通過put和commit來成功執行,而第二個進程將引發記錄的ConcurrentModificationException。

編輯2:增加計數器(並可能拋出異常)的事務也必須創建新記錄。這樣,如果引發異常,則不會創建新記錄。

+1

謝謝馬丁。我已經研究過你提供的鏈接。沒有示例代碼,我很難理解你的建議。在你提供的鏈接中,事務可以處理這種情況,因爲拋出了異常。在我的情況下,沒有例外。我獲取用戶的所有記錄並按日期過濾,即使該記錄應該存在,也找不到。因此它創建了一個新的記錄與該日期。沒有例外。交易如何解決這個問題? – Houman

+0

感謝馬丁,如果我錯了,請糾正我,但我不認爲這是關於多個進程試圖同時保存。問題是在這一行罕見情況下找不到記錄'recordsdb = FeelTrackerRecord.query(ancestor = user.key).filter(FeelTrackerRecord.record_date == date_parser.parse(json_record ['record_date']))'因此它跳轉到'else if'語句並創建一條新記錄。那就是創建複製條目的時刻。它不是更新記錄,而是創建一個新記錄。我們不得不找到它沒有找到第一個記錄的原因嗎? – Houman

+0

我明白你的意思,併爲此編輯2添加了一個建議。 –