这里的最新文档 code.google/ appengine / docs / java / datastore / transactions.html 指出:如果您的应用程序在提交事务时收到异常,并不总意味着事务失败,您可以收到DatastoreTimeoutException,ConcurrentModificationException,或DatastoreFailureException在事务已被提交并最终成功应用的情况下发生异常。只要有可能,使您的Datastore事务处于幂等状态,这样如果重复事务,最终结果将是相同的。
解决方案
几个注释:
正如文档所说 - 您无法确定是否应用了交易。这是问题的核心。
使其具有幂等性 - 意思是说,如果您调用它两次,则无关紧要。在支付交易的情况下,您将创建支付交易实体。对于每一笔交易,您都会使用付款数据创建一个特殊实体并将其写入数据存储。这里的关键是从付款数据中生成一个自然ID:用户ID,来源账户,付款金额,目标账户,日期/小时/分钟。然后,如果交易重复,它将创建一个具有相同ID的支付交易实体,并将覆盖旧交易实体 - 这意味着如果只有一个或两个交易完成,结果将是相同的。 (然后通过一系列交易并将其添加到开户金额来计算用户账户的余额 - 这是银行在实践中实际做的AFAIK)。
The latest documentation here code.google/appengine/docs/java/datastore/transactions.html states: "If your app receives an exception when submitting a transaction, it does not always mean that the transaction failed. You can receive DatastoreTimeoutException, ConcurrentModificationException, or DatastoreFailureException exceptions in cases where transactions have been committed and eventually will be applied successfully. Whenever possible, make your Datastore transactions idempotent so that if you repeat a transaction, the end result will be the same."
解决方案
Few notes:
As docs say - you can not be sure if transaction was applied. That is the core of the problem.
Just rollback in case of all exceptions. See this example: code.google/appengine/docs/java/datastore/transactions.html#Isolation_and_Consistency
Make it idempotent - meaning if you invoke it twice, it does not matter. In the case of payment transactions, you make "payment transaction" entity. For every transaction you make a special entity with payment data and write it to datastore. The key here is to generate a natural ID from payment data: user ID, source account, payment amount, target account, date/hour/minute. Then if transaction is repeated, it will create a payment transaction entity with the same ID and will overwrite the old one - which means the result will be the same if only one or two transactions were completed. (The balance of the user account is then calculated by going through a series of transactions and adding it to the opening amount - this is what banks actually do in practice AFAIK).
更多推荐
事务和ConcurrentModificationException文档含糊不清
发布评论