1. ホーム

hibernate の遅延ロード例外分析: ロールのコレクションの遅延初期化に失敗しました。

2022-02-14 23:33:47

初期環境: hibernate 各ユーザーはグループに対応する。 


グループコードスニペット

@OneToMany(mappedBy="group" )
	@JoinColumn(name="group")
	public Set<User> getUsers() {
		return users;
	}









ユーザーコードスニペット

@ManyToOne
	@JoinColumn(name="group")
	public Group getGroup() {
		return group;
	}









このコードを実行すると

	@Test
	public void testGetGroup(){
		//testSaveGroup();
		
		Session se=sf.getCurrentSession();
		se.beginTransaction();
		Group g=(Group)se.get(Group.class, 1);
		
		se.getTransaction().commit();
		for(User u : g.getUsers()){
			//g.getUsers() 
			System.out.println("------------------");
			System.out.println(u.getName());
		}
	}





例外が発生します。

18:26:28,624 ERROR org.hibernate.LazyInitializationException:42 - failed to lazily initialize a collection of role: com.hibernate.crud.Group. users, no session or session was closed
LazyInitializationException: failed to lazily initialize a collection of role: com.hibernate.crud.Group.users, no session or session was closed session was closed
	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380)
	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected( AbstractPersistentCollection.java:372)
	at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:365)
	at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:108)
	at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:186)
	at com.hibernate.crud.test.testGetGroup(test.java:69)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
	at org.junit.internal.runners.statistics.RunBefores.evaluate(RunBefores.java:28)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)






遅延ロード例外とも呼ばれる
failed to lazily initialize a collection of role: com.hibernate.crud.Group.users, no session or session was closed





<スパン 馬兵衛さんの説明で、頻発するフォーメーションの理由が基本的に理解できたので、今度は個人的なメモとして、一般的な話をします。

<スパン というのも Hibernate AnnotationのデフォルトのFetchTypeは、ManyToOneではEAGER、OneToManyではLAZYです。

つまり、このコードでは、UserはFetchType.EAGER.で、GroupはFetchType.LAZY.です。

具体的には、このコードでは

@Test
	public void testGetGroup(){
		//testSaveGroup();
		
		Session se=sf.getCurrentSession();
		se.beginTransaction();
		Group g=(Group)se.get(Group.class, 1);
		
		se.getTransaction().commit();
		for(User u : g.getUsers()){
			//g.getUsers() 
			System.out.println("------------------");
			System.out.println(u.getName());
		}
	}





実行 
Group g=(Group)se.get(Group.class, 1);

クエリの結果は

 select group0_.id as id1_0_, group0_.name as name1_0_ from t_group group0_ where group0_.id=?

groupsテーブルのデータのみ。

そして、実行するために


for(User u : g.getUsers()){    



まだデータベースに接続する必要がありますが、セッションはすでにコミットされ、閉じられています。そのため、failed to lazily initialize a collection of roles exceptionが報告されます。



この問題を解決するには 1. グループにFetchType.EAGERを設定し、対応するUserテーブルを取得し、キャッシュすることができます。以下のようになります。

@OneToMany(mappedBy="group",fetch=FetchType.EAGER )
	@JoinColumn(name="group")
	public Set<User> getUsers() {
		return users;
	}








2. Place the commit at the end. As follows.






@Test public void testGetGroup(){ //testSaveGroup(); Session se=sf.getCurrentSession(); se.beginTransaction(); Group g=(Group)se.get(Group.class, 1); for(User u : g.getUsers()){ //g.getUsers() System.out.println("------------------"); System.out.println(u.getName()); } se.getTransaction().commit(); } I'm learning hibernate now, and will update it later with other methods or errors.
@Test
	public void testGetGroup(){
		//testSaveGroup();
		
		Session se=sf.getCurrentSession();
		se.beginTransaction();
		Group g=(Group)se.get(Group.class, 1);
		
		for(User u : g.getUsers()){
			//g.getUsers() 
			System.out.println("------------------");
			System.out.println(u.getName());
		}
		se.getTransaction().commit();
	}
	


I'm learning hibernate now, and will update it later with other methods or errors.