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 にあります。
誰にもアイデアはありますか?
感謝をこめて !