2012-01-03 3 views
6

私は公式のGAE documentation on transactionsを読んでおり、ConcurrentModificationExceptionがスローされたときはわかりません。私はコピー&ペーストをここにいる例の一つでGAEでConcurrentModificationExceptionがスローされるのはいつですか?

ルック:

int retries = 3; 
while (true) { 
    Transaction txn = datastore.beginTransaction(); 
    try { 
     Key boardKey = KeyFactory.createKey("MessageBoard", boardName); 
     Entity messageBoard = datastore.get(boardKey); 

     long count = (Long) messageBoard.getProperty("count"); 
     ++count; 
     messageBoard.setProperty("count", count); 
     datastore.put(messageBoard); 

     txn.commit(); 
     break; 
    } catch (ConcurrentModificationException e) { 
     if (retries == 0) { 
      throw e; 
     } 
     // Allow retry to occur 
     --retries; 
    } finally { 
     if (txn.isActive()) { 
      txn.rollback(); 
     } 
    } 
} 

は、(この例では)データストアへのすべての書き込みは、トランザクションの下で包まれています。では、なぜConcurrentModificationExceptionが投げられるのですか?

トランザクションでラップされていない他のコードが上記のコードで変更されているのと同じエンティティを更新すると、発生しますか?エンティティを更新するすべてのコードが常にトランザクションでラップされることを保証すれば、ConcurrentModificationExceptionを取得しないことが保証されますか?

答えて

1

GAEメーリングリストで回答が見つかりました。

GAEでの取引の仕組みについて誤解を感じました。私は、トランザクションを開始すると、トランザクションがコミットするまで、データストアへの同時更新をロックアウトすると想像していました。これは、すべての更新がこの取引でブロックされるため、パフォーマンスの悪夢となりました。これが当てはまらないことは幸いです。

代わりに、最初の更新が優先され、その後の更新で衝突が検出された場合は例外がスローされます。

これは、多くのトランザクションがリトライロジックを必要とすることを意味するため、私は最初は驚きました。 PostgreSQLでは、個々の行と列をロックするオプションがありますが、PostgreSQLの「直列化可能な分離」レベルのセマンティクスに似ています。

+0

私は提供した見積もりの​​第2段落とどう違うのですか? – Kiril

+0

Lirik、それはあなたが含まれている引用とあまり変わらない。しかし、見積もりの​​下の要約は私のものとは異なり、答えにはいくつかの前提と無関係な引用があります。それで、私は自分の混乱を明確にしながら新鮮な答えを出しました。このクエストに参加してくれてありがとう。 – HRJ

+0

さて、重要なことはあなたに答えがあることです:)... – Kiril

0

あなたが彼らが提案する何をやっているようだが行うべきではありません。http://code.google.com/appengine/docs/java/datastore/transactions.html#Uses_for_Transactions

警告!上記のサンプルは、簡単にするためにトランザクション的にカウンタをインクリメントすることを示しています。あなたのアプリに頻繁に更新されるカウンタがある場合、トランザクションを増やすべきではありません。カウンターを操作するベストプラクティスは、カウンターシャージングと呼ばれる手法を使用することです。

おそらく、上記の警告が適用されませんが、何あなたが見ている問題を示唆しているようだ後、次のとおりです。

値によって更新することができるので、これはトランザクションを必要としこのコードの後の別のユーザーはオブジェクトをフェッチしますが、変更されたオブジェクトを保存する前にそのオブジェクトをフェッチします。トランザクションがなければ、ユーザーの要求は他のユーザーの更新前にcountの値を使用し、保存によって新しい値が上書きされます。トランザクションでは、アプリケーションは他のユーザーの更新について通知されます。エンティティがトランザクション中に更新された場合、トランザクションは、ConcurrentModificationExceptionで失敗します。アプリケーションは、新しいデータを使用するためにトランザクションを繰り返すことができます。

つまり、トランザクションを使用して同じエンティティを更新すると同時にトランザクションを使用せずにエンティティを変更しているようです。

注:ごくまれに、トランザクションがタイムアウトまたは内部エラー例外を返す場合でも、トランザクションは完全にコミットされます。このような理由から、可能なときはいつでもトランザクションを冪等化するのが最善です。

公正警告:私は図書館に慣れていないんだけど、上記の引用符は、(あなたは、元の質問に投稿したものと同じと思われる)のサンプル取引を示す文書から採取しました。

+0

この警告は、まったく別の理由によるものです。つまり、パフォーマンスです。トランザクションのコンテキストでは、これは完全に有効な例です。 – HRJ

+0

HRJ、警告の後の段落では、エンティティがトランザクション中に更新されると、トランザクションが 'ConcurrentModificationException'で失敗することも示されています。私はこれがこの場合起こっていると推測します。 – Kiril

+0

質問にお答えいただきありがとうございます。私はすでにドキュメントの内容を知っています。私は仮定なしで答えが必要です。 – HRJ

関連する問題