3

Glassfish サーバーの 1 つで奇妙な問題が発生しました。このコードを見てください:

userTransaction.begin();

MyEntity entity = new MyEntity(12345);
//setting values..
entityManager.persist(entity);

MyEntity persistedEntity = entityManager.createQuery("SELECT p FROM MyEntity p WHERE p.idpk=12345").getSingleResult();
//...

userTransaction.commit(); //OK => the tuple is in the DB

ここでビジネス上の問題が発生し、トランザクションをロールバックする必要があります。

userTransaction.begin();

MyEntity entity = new MyEntity(12345);
//setting values..
entityManager.persist(entity);

MyEntity persistedEntity = entityManager.createQuery("SELECT p FROM MyEntity p WHERE p.idpk=12345").getSingleResult();
//...

//Business problem => rollback
userTransaction.rollback(); //ERROR => the tuple 12345 is in the DB !

ロールバックが機能しているように見えても (例外は発生せず、奇妙なログ出力もありません)、タプルはデータベースにコミットされています... 問題の場所を検索するために、次のコードを試しました。

userTransaction.begin();

MyEntity entity = new MyEntity(12345);
//setting values..
entityManager.persist(entity);

//Business problem => rollback
userTransaction.rollback(); //OK => the tuple 12345 is NOT in the DB !

このコード (エンティティは取得されません) では、タプルはデータベースにコミットされません。これは正しい動作です。さらに進みましょう:

userTransaction.begin();

MyEntity entity = new MyEntity(12345);
//setting values..
entityManager.persist(entity);

MyEntity persisted = entityManager.find(MyEntity.class, 12345);
//...

//Business problem => rollback
userTransaction.rollback(); //OK => the tuple 12345 is NOT in DB

この最後のケースでも、結果は正しく、データベースにコミットされたタプルはありません。クエリでエンティティを取得するときに、EntityManager が魔法の [不要な] コミットを行うようです...別のテーブルでクエリを作成しようとしましたが、間違ったコミットは発生しません (ロールバックが機能します)。さらに、自分のサーバーで問題を再現しようとしましたが、問題はありません。すべてのロールバックが正しく機能しています。したがって、実際にはサーバー構成の問題であるはずです。

参考までに、これは Linux で動作するグラスフィッシュ v2.1.1 です。EntityManager は FlushModeType.AUTO にあります。

誰にもアイデアはありますか?

感謝をこめて !

4

3 に答える 3

2

あなたが見ているもののいくつかを説明しているように見えるいくつかの議論を見つけました:

アクションブックのEJB3のP-331経由:

デフォルトでは、データベース フラッシュ モードは AUTO に設定されています。これは、Entity-Manager が必要に応じて自動的にフラッシュ操作を実行することを意味します。通常、これは、トランザクション スコープの EntityManager のトランザクションの終了時、およびアプリケーション管理または拡張スコープの EntityManager の永続コンテキストが閉じられたときに発生します。さらに、保留中の変更があるエンティティがクエリで使用されている場合、永続化プロバイダーはクエリを実行する前に変更をデータベースにフラッシュします。 フラッシュ モードが COMMIT に設定されている場合、持続性プロバイダーは、トランザクションがコミットされたときにのみデータベースと同期します。ただし、クエリを実行する前にエンティティの状態をデータベースと同期する必要があるため、これには注意が必要です。これを行わず、EntityManager クエリがデータベースから古いエンティティを返すと、アプリケーションが一貫性のない状態になる可能性があります。

P-353 EJB3 のアクション ブックには次のように記載されています。

クエリが FlushModeType.COMMIT に設定されている場合、永続化コンテキストでエンティティに対して行われた更新の効果は仕様によって定義されておらず、実際の動作は実装固有です。

おそらく、返されたクエリでフラッシュモードを切り替えてみてください

entityManager.createQuery("SELECT p FROM MyEntity p WHERE p.idpk=12345").getSingleResult();

またはエンティティマネージャー自体で、それが何かを変えるかどうかを確認しますか?

ここでさらに議論します:

http://www.coderanch.com/t/475041/ORM/databases/EntityManager-setFlushMode-COMMIT-Vs-Query

于 2012-08-30T17:11:51.083 に答える
0

なぜこれをしないのですか?

MyEntity persisted = entityManager.persist(entity);
于 2012-08-31T05:47:37.743 に答える
0

私は最終的にどこに問題があるのか​​ を見つけました.JDBC接続プールには、オプション「非トランザクション接続」が有効になっているセクション「トランザクション」があります...このオプションを削除するだけで、すべてが機能しました:)

于 2013-07-09T08:44:14.013 に答える