2017-02-03 3 views
0

春を使って簡単な休憩アプリケーションを開発中です。(Spring)JPA/Hibernateの奇妙な振る舞い

私はSpringの@Scheduledアノテーションを使って定期的に実行するメソッドを実装しようとしています。 私は、外部APIからデータを取得し、それをdatabse(Spring Jpaリポジトリ、CrudRepositryを拡張)に格納する方法を持っていました。私が持っているエンティティは、会社とレポートです(会社には多くのレポートがあります)。

た問題イムはこれです:

私は(簡単なテスト用)コントローラからそのupdateメソッドを呼び出していましたが、今私はそれが自分自身で実行されるように、私のスケジューリングクラスからそれを呼びたい開始します。私は、コントローラからメソッドを呼び出したときに

org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: Models.Company; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: Models.Company 

これは実現しなかったとそれがない理由を私は知らない。私は(それを修正することなく)コードを移動し、shcedulerから呼び出され、そのときしかし、私はこの例外を取得します今。

これは、両方のケースで使用してコードイムです:

updateReportsメソッド内
ReportsManager reportsManager = new ReportsManager(); 
    reportsManager.updateReports(resultRepository, companyRepository.findAll()); 

私はこのような何か:

List<BasicReport> resultsList = new ArrayList<>(); 

反復企業のリストオーバーをし、レポートオブジェクトを作成します。

BasicReport currentResult = new BasicReport(); 
    currentResult.setReportName(request.getReportName()); 
    currentResult.setCompany(request.getCompany()); 
    resultsList.add(currentResult); 

次に、そのリストを他の場所に保存します。

repository.save(currentResults); 

私はどちらの場合も同じコードを使用して別の結果を得ているということです。 アイデア ありがとう

編集:@ user152468のコメントと@Driesを読んだ後、私は@Transactionalアノテーションを自分のスケジューラクラスとその動作の不思議に追加しました。 @transactinal注釈は、EntityManagerをスレッドにバインドすると推測しています。おかげさまで

+0

私は '@ scheduled'アノテーションがspring' @ transactional'アノテーションではうまくいきません。 Springはこれらのクラスからプロキシを構築し、同じメソッドで両方のアノテーションを処理することはできません。 – user152468

+0

@transactionalアノテーションはどこでも使用していませんが、 – Juan

+0

@RestControllerなどを使用すると暗黙的になる可能性があります。 – user152468

答えて

0

コントローラからの使用の場合、要求が実行されている期間全体にわたってEntityManagerを開き、レポートを生成する公開エンティティマネージャーインビューパターンがあります。

スケジュールされた方法で実行している場合は、使用しているEntityManagerを現在のスレッドにバインドしていない可能性があります。したがって、メソッドが実行されてレポートが生成されるまで開いていません。つまり、あなたのDAOコードではオンデマンドで開きますが、そのメソッドから戻るとエンティティが切り離されることになります。

EntityManagerHolderのインスタンスを指定するTransactionSynchronisationManagerbindResource関数を使用してみてください。基本的にOpenEntityManagerInViewInterceptorが何をしているのか、ソースを調べて同様のアプローチを作ることができます。それは89行目です。