エラー内容
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: demo.model.CommunitySet.communites, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:602)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:217)
これは、コレクション(Entityのフィールド)の値をDBから取得しようとしたがDBのセッションが無い(切断されている)、という時に発生します。
つまり、トランザクションの外側でEntityのフィールドの値を取得しようとすると発生します。
問題箇所
List<CommunitySet> sets = communitySetRepository.findAll();
for (CommunitySet set : sets) {
String setname = set.getName();
Set<Community> communites = set.getCommunites();
System.out.println(communites.size()); // ★★ 関連エンティティにアクセスを試みるも、トランザクションが切れているので、エラーとなる
}
原因
@Transactional
をつけ忘れていた。
@Transactional
をつけないと、各データアクセスメソッド(findAll()やsave()など)の実行時のみAUTOCOMMITが有効になります。
つまり、データアクセスメソッドが終了するとトランザクションが無効になります。
無効になっているにも関わらず関連エンティティの取得を試みたためエラーが発生しました。
対象となるクラス、もしくはメソッドに@Transactional
をつければ解決しました。
@Transactional
を付ける場所の例
クラス変数でDBから取得するデータを使用している時は、クラスにつける。
@Transactional
public class MigrationService {
Type type1 = null;
public boolean migration() throws IOException {
type1 = typeRepository.getByName("type1");
}
メソッド内だけで使用しているときは、メソッドにつける。(クラスにつけても大丈夫)