LoginSignup
7
3

More than 3 years have passed since last update.

Spring LazyInitializationException: no Session

Last updated at Posted at 2019-07-26

エラー内容

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");
    }

メソッド内だけで使用しているときは、メソッドにつける。(クラスにつけても大丈夫)

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3