2017-09-23 67 views
1

的GAE文檔警告:在GAE中,如何賺錢轉賬交易冪等?

只要有可能,讓您的數據存儲區事務冪等,這樣,如果你重複交易,最終的結果將是相同的。

假設我想兩個人之間轉移的錢數:

class User(ndb.Model): 
    balance = ndb.IntegerProperty(default=0) 

@ndb.transactional(xg=True) 
def transfer(from_key, to_key, amount) 
    from = from_key.get() 
    to = to_key.get() 
    from.balance -= amount 
    to.balance += amount 
    ndb.put_multi([from, to]) 

,因爲這不是冪等,它可能發生一次以上,並導致一個問題。我想重構這個以確保交易是冪等的。

answer提出了一種解決方案:

爲了解決這個問題,你可以通過創建一個「事務密鑰」,並記錄在一個新的實體鍵作爲交易的一部分冪等交易。第二個事務可以檢查該事務密鑰,如果找到,將不會執行任何操作。一旦您完成交易或您放棄重試,交易密鑰可以被刪除。

但我不明白如何實現它。

有人可以解釋如何使這種交易冪等?

+1

閱讀這篇舊文章。雖然在appengine中有很多新功能之前寫過,但仍然值得關注,作爲實施您嘗試執行的指南。 http://blog.notdot.net/2009/9/Distributed-Transactions-on-App-Engine –

回答

1

,你可以創建一個基於交易細節的關鍵,例如:

import datetime 
import hashlib 

>>> txn = { 
    'from_account': '100123', 
    'to_account': '200456', 
    'amount': 123456, 
    'timestamp': datetime.datetime(2017, 9, 23, 10, 11, 12, 123456) 
} 

# Combine the values into a string 
>>> raw_key = u''.join([unicode(v) for k, v in sorted(txn.items())]) 

>>> print raw_key 
12345610-09-23 10:11:12.123456200456 

# hash the key so exposing it in logs etc. doesn't expose transaction data 
>>> key = hashlib.sha256().hexdigest() 
>>> print key 
261c516faa580d6604850967c5804f3fce5f323aae90e36debdb84aa0b950dcb 

您可以將數據存儲中的哈希鍵,或使您的交易模型的計算性能,如果你有一個,並在嘗試創建新事務之前進行查詢。

class TransactionKeys(ndb.model): 
     pass 


class TransactionHandler(webapp2.RequestHandler): 

    def post(self): 
     txn = { 
      'from_account': self.request.POST['from'], 
      'to_account': self.request.POST['to'], 
      'value': self.request.POST['value'] 
      'timestamp': datetime.datetime.now() 
     } 
     raw_key = u''.join([unicode(v) for k, v in sorted(txn.items())]) 
     txn_key = hashlib.sha256().hexdigest() 
     ... 
     transfer(from_key, to_key, amount, txn_key) 


@ndb.transactional(xg=True) 
def transfer(from_key, to_key, amount, txn_key) 
    already_exists = TransactionKeys.get_by_id(txn_key) 
    if already_exists: 
     raise DuplicateTransactionError('Duplicate transaction!') 
    else: 
     transaction_key = TransactionKey(id=txn_key) 
    from = from_key.get() 
    to = to_key.get() 
    from.balance -= amount 
    to.balance += amount 
    ndb.put_multi([from, to, txn_key]) 

這種方法並不完美 - 例如,如果兩個相同的事務以相同的微秒到達,它將失敗。您可以添加其他數據以使密鑰更加唯一,例如App Engine實例ID或請求ID。

最後,強制性免責聲明:我不是安全專業人士,如果您使用真錢進行此操作,您應該執行適當的盡職調查並考慮專業賠償/公共責任保險。

+0

你可以擴展你將如何使用密鑰? (我的情況其實並不是危險的,但匯款是一個簡單的例子,可以讓你知道。) –

+0

@ JeffO'Neill示例代碼添加 – snakecharmerb

+0

您可以使用隨機UUID作爲txn鍵,因爲您從不使用密鑰中的信息?另外,似乎你可以刪除'post'末尾的'TransactionKeys'實體來清理。 –