私はアプリケーションエンジンでJDO 2.3を使用しています。私はローカルテストのためにマスター/スレーブデータストアを使用していましたが、最近ローカルテストにHRDデータストアを使用するように切り替えました。私のアプリケーションの一部は壊れています(これは予想されます)。アプリが壊れている部分の1つは、たくさんの書き込みをすばやく送信する場所です。これは1秒の制限があるため、同時の変更の例外で失敗しています。コミットされたJDOの書き込みは、ローカルGAE HRD、または場合によっては再利用されたトランザクションには適用されません。
これも期待していますので、後で書き込みが失敗したときにブラウザが再試行してしまいます(おそらく、最高のハックではないかもしれませんが、すぐに動くようにしようとしています)。
しかし、奇妙なことが起こっています。コミットフェーズが完了し、要求が私の成功コードを返すにもかかわらず、成功するはずの書き込み(同時の変更例外を受け取らないもの)も失敗します。再試行されたリクエストは正常に動作していることがログからわかりますが、最初の試行でコミットしたと思われるこれらのリクエストは、決して「適用されません」。しかし、私が「適用」フェーズについて読んだことから、同じエンティティに再度書き込むと、適用を強制するはずですが、そうではありません。
コードが続きます。注意すべき事項:
- automatic JDO cachingを使用しようとしています。そこで、JDOはmemcacheを使っています。これは、トランザクション内のすべてをラップしない限り、実際には機能しません。
- エンティティから文字列を読み込み、文字列の一部を変更し、その文字列をエンティティに保存し直すことです。これらのリクエストがトランザクションに含まれていない場合は、もちろん「ダーティリード」の問題があります。しかし、トランザクションでは、分離は "シリアライズ可能"のレベルにあるはずですので、私はここで何が起こっているのか分かりません。
:PersistenceManager pm = PMF.getManager(); Transaction tx = pm.currentTransaction(); String responsetext = ""; try { tx.begin(); // I have extra calls to "makePersistent" because I found that relying // on pm.close didn't always write the objects to cache, maybe that // was only a DataNucleus 1.x issue though Key userkey = obtainUserKeyFromCookie(); User u = pm.getObjectById(User.class, userkey); pm.makePersistent(u); // to make sure it gets cached for next time Key mapkey = obtainMapKeyFromQueryString(); // this is NOT a java.util.Map, just FYI Map currentmap = pm.getObjectById(Map.class, mapkey); Text mapData = currentmap.getMapData(); // mapData is JSON stored in the entity Text newMapData = parseModifyAndReturn(mapData); // transform the map currentmap.setMapData(newMapData); // mutate the Map object pm.makePersistent(currentmap); // make sure to persist so there is a cache hit tx.commit(); responsetext = "OK"; } catch (JDOCanRetryException jdoe) { // log jdoe responsetext = "RETRY"; } catch (Exception e) { // log e responsetext = "ERROR"; } finally { if (tx.isActive()) { tx.rollback(); } pm.close(); } resp.getWriter().println(responsetext);
- エンティティが変更されて、私は、クロスグループトランザクションは
関連するコード(これは単純化されたバージョンである)を有効にしている(いないグループで)ルートエンティティ
更新:なぜこのようなことが起こっているのか、私は確信していますが、それでも確認できる人に賞金を授与します。
基本的に、トランザクションは実際にはデータストアのローカルバージョンで実装されていないという問題があると思います。参考文献:トランザクションが実装されていませんので
https://groups.google.com/forum/?fromgroups=#!topic/google-appengine-java/gVMS1dFSpcU https://groups.google.com/forum/?fromgroups=#!topic/google-appengine-java/deGasFdIO-M https://groups.google.com/forum/?hl=en&fromgroups=#!msg/google-appengine-java/4YuNb6TVD6I/gSttMmHYwo0J
、ロールバックは基本的に何もしません。したがって、2つのトランザクションが同時にレコードを変更しようとすると、不正な読み取りが行われます。つまり、Aはデータを読み取り、Bは同時にデータを読み取ります。 Aはデータの変更を試み、Bはデータの異なる部分の変更を試みます。 Aはデータストアに書き込み、次にBはAの変更を消去します。その後、Bはアプリエンジンによって「ロールバック」されますが、ローカルデータストアで実行中のロールバックは実行されないため、Bの変更はそのまま残り、Aは実行しません。一方、Bは例外をスローしたスレッドであるため、クライアントはBを再試行しますが、Aは再試行しません(Aは成功したトランザクションだったため)。
ネイティブな方法を学ぶ価値がある、あなたはより多くの1秒に1回以上、同じエンティティグループに永続化を避けるために、データストアとどのようにあなたがそれを使用するの再設計を考えたことがありますか?また、タスクをエンキューするためにデータストアに永続化を渡してみましたか、1/sエンティティグループ書き込み頻度制限を尊重するように設定しましたか? –
私はそれを考えました。しかし、私がそれをする前に、なぜこの特定のバグが起こっているのか理解したいと思います...私の懸念は、HRDやアプリエンジン/ jdoトランザクションや何かについて基本的に何かを理解していないか、ドキュメント、そして私は、現在のプラグイン(GAEを使用して、私はにトランザクションを追加する必要があり、少なくとも25個の他のサービス(データストアアクセスはトランザクション内にない場合JDOのキャッシュは動作しません) – eeeeaaii
FWIWを、持っているので、後で私を噛まないように起こっていますJDO v2.x)、私はL2キャッシュが動作するためのトランザクションにアクセスする必要はないと考えています。もしオブジェクトが読み込まれてL2キャッシュされていれば、それが報告されなければなりません(明らかに古いプラグインはサポートされていません。 – DataNucleus