web-dev-qa-db-ja.com

@Transactionalがデータベースに自動的に保存されるのはなぜですか

@Transactionalアノテーションが付けられたメソッドがあります。 DBからオブジェクトを取得し、フィールドを変更してから、メソッドから戻ります。オブジェクトを保存しないと、とにかくデータベースが更新されますが、これは奇妙なことです。

この振る舞いを避ける方法を教えてください。

20
Rachidon

この動作は、トランザクション性の主な目的の1つです。

トランザクションメソッドが返される前に、トランザクションがコミットされます。つまり、管理対象エンティティへのすべての変更がデータベースにフラッシュされます。

エラーが発生した場合、トランザクションはロールバックされます。つまり、変更はデータベースにコミットされません。

遅延ロードされたプロパティ(おそらくエンティティからのコレクション)にアクセスしようとすると、おそらくLazyInitializationExceptionを取得します。 DBからエンティティをフェッチするときに、レイジーロードされたプロパティはインスタンス化されません。

トランザクションで遅延ロードされたプロパティにアクセスすると、永続性プロバイダーがクエリを作成し、結果をインスタンス化して、「親」エンティティに添付します。

編集:レイジープロパティをロードし、変更をDBに保持せずにエンティティを変更できるようにする場合は、レイジープロパティのフェッチ結合を使用してエンティティをフェッチできます。

_em.createQuery("SELECT e FROM MyEntity e JOIN FETCH e.lazyProp");
_

次に、@ oridで説明されている方法の1つに進みます。

フェッチ結合を使用していない場合は、トランザクション内で遅延ロードされたプロパティにアクセスする必要があります。

_myEntity.getLazyProp().size();
_

size()の呼び出しに注意してください。プロキシを取得するため、ゲッターを呼び出すだけでは不十分です。プロパティからの実際のデータを必要とする操作を実行する必要があります。

15
kostja

これは通常のJPAの動作です。

find()などを介してオブジェクトを取得すると、そのオブジェクトはアタッチされていると見なされるか、永続コンテキストに属します。メソッドを終了すると、@TransactionalはSpringトランザクション管理アスペクトをトリガーし、すべての「ダーティ」オブジェクトをデータベースにフラッシュしてトランザクションをコミットします。オブジェクトは永続コンテキストとトランザクションのコンテキスト内ですでに変更されているため、saveメソッドを明示的に呼び出す必要がなくても、変更はデータベースに保存されます。

データベースに影響を与えずにオブジェクトを変更する場合は、次の2つのオプションがあります。

  1. @Transactionalアノテーションが付けられたメソッドから戻った後、フィールドを更新します
  2. メソッドを使用しない場合は、エンティティマネージャで detach を呼び出します
13
Ori Dar