18

作業中のアプリを AspectJ ロード時間織りの使用から Spring CGlib プロキシの使用に切り替えました。その直後にコードの多くの部分で休止状態の遅延読み込み例外が発生し始めましたが、過去には例外はありませんでした。投げた。

これらの遅延読み込みの例外@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)は、トランザクション属性を持たず、データベースからデータを読み取るためのスプリング リポジトリと呼ばれる、以前は公開されていた一連のメソッドを追加することで解決できました。

追加@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)すると休止状態の遅延読み込みの例外がなくなる理由と、これらの注釈が AspectJ の読み込み時間の織り方では必要ないのに、out なしでは必要な理由を知っている人はいますか?

更新 2 AspectJ を削除することは問題ではないと思いますが、問題は、SUPPORTS 伝播の実際の動作をよく理解していなかったことです。特に、SUPPORTS が JPA EntityManager とどのようにやり取りしたかということで、遅延読み込み例外の原因となった SUPPORTS 伝播の束を削除しました。Spring Transaction Manager のソース コードを読んだ後、何をすべきかがすべて明確になりました。Spring のドキュメントがあまりよく指摘していない重要なアイデアは、@Transactional アノテーションが、EntityManager のライフサイクルをトランザクション メソッドの開始と終了に結び付ける同期ポイントとして使用されるということです。また、この一連の記事 ( http://www.ibm.com/developerworks/java/library/j-ts1/ ) およびこのブログ記事も強くお勧めします。http://doanduyhai.wordpress.com/2011/11/21/spring-persistencecontext-explained/

更新 1

これは、AOP プロキシを経由しないプライベート @Transactional メソッドへの呼び出しの場合ではありません。これらの問題は、他のサービスから呼び出されているパブリック メソッドで発生しています。

問題が発生しているコード構造の例を次に示します。

@Service
public class FooService 
{
   @Autowired
   private BarService barService;

   public void someMethodThatOnlyReads() {
      SomeResult result = this.barService.anotherMethodThatOnlyReads()

      // the following line blows up with a HibernateLazyLoadingEcxeption 
     // unless there is a @Transactional supports annotation on this method
      result.getEntity().followSomeRelationship(); 
    }

}

@Service
public class BarService 
{
   @Autowired
   private BarRepository barRepo;

   public SomeResult anotherMethodThatOnlyReads()
   {
      SomeEntity entity =  this.barRepo.findSomeEntity(1123);
      SomeResult result = new SomeResult();
      result.setEntity(entity);
      return result; 
    }
}

@Repository
public class BarRepository 
{
   @PersistenceContext
   private EntityManager em;

   public SomeEntity findSomeEntity(id Integer)
   {
      em.find(SomeEntity.class,id);
   }
}
4

2 に答える 2

10

あなたのコードは使用していないOpenSessionInViewFilterか、同様のものを使用していないと思います。

注釈がない場合、Hibernate セッションはメソッド@Transactionalを離れた後に閉じられます。BarRepository.findSomeEntity()

@Transactionalメソッドが呼び出され、( TransactionalInterceptorcglib プロキシまたは Spring コンテキストにある他の A​​OP 構成を介して) メソッドに適切にバインドされると、セッションは注釈付きメソッド全体に対して Spring によって開かれたままになり、したがって、遅延読み込みの例外。

If you turn up the logging to DEBUG on the org.springframework.transaction and org.springframework.orm.hibernate3 (or hibernate4 if you are on Hibernate 4) loggers, particularly the HibernateTransactionManager class and org.springframework.transaction.support.AbstractPlatformTransactionManager, you should see exactly at which points in the code flow Spring is deciding it needs to open and close the Hibernate Session. The logs should also show why a session or transaction is opened/closed at each point.

于 2013-05-15T01:31:56.217 に答える
8

なぜそうなるのかは完全にはわかりませんが、私の理論は次のとおりです。

AspectJ ウィービングから CGLIB プロキシに移行@Transactionalすると、同じオブジェクトから呼び出されたメソッドに配置された注釈が無効になります。これは、これらのメソッド内のコードが非トランザクションで実行されることを意味し@Transacionalます (コール スタックに別のメソッドが@Transacional実際に有効になる場合を除きます)。

Javadoc forPropagation.SUPPORTSは次のように述べています。

注: トランザクション同期を使用するトランザクション マネージャーの場合、PROPAGATION_SUPPORTS は、同期が適用されるトランザクション スコープを定義するため、トランザクションがまったくない場合とは少し異なります。結果として、同じリソース (JDBC 接続、Hibernate セッションなど) が指定されたスコープ全体で共有されます。これは、トランザクション マネージャーの実際の同期構成に依存することに注意してください。

そのため、コードが非トランザクションで実行Sessionされる場合、オブジェクトのロードに使用される Hibernate は、その後の遅延プロパティの初期化には使用できません。コード スタックの最上位メソッドに で注釈を付けると@Transactional(propagation = Propagation.SUPPORTS)、そのメソッドを終了するまで HibernateSessionを使用できます。

于 2013-04-17T14:54:27.137 に答える