Java Hibernate LazyInitializationException 仅在仅使用 JUnit 运行时出现

Posted

技术标签:

【中文标题】Java Hibernate LazyInitializationException 仅在仅使用 JUnit 运行时出现【英文标题】:Java Hibernate LazyInitializationException only when running with JUnit only 【发布时间】:2021-04-28 21:02:59 【问题描述】:

我在一个 API 项目中使用 Java + Spring boot(Ver 2.1.16) + Hibernate + JPA。 我有几个具有多个 OneToMany 关系的模型。 我没有提到获取类型,但根据我使用的 Hibernate 版本,我知道它默认为 Eager。 我在我的服务方法中也提到了@Transactional。 当我通过 Postman 获取对 API 端点的数据调用(我收到包括 OneToMany 在内的所有字段)时,一切都很好,没有任何例外。 但是当我通过单元测试调用服务方法时,我得到了以下异常。

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.ccc.common.model.InstantiatedVnfInfo.vnfcInfo, 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)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:581)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:148)
at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:624)
at java.base/java.lang.String.valueOf(String.java:3367)
at java.base/java.lang.StringBuilder.append(StringBuilder.java:167)
at org.junit.Assert.failNotNull(Assert.java:755)
at org.junit.Assert.assertNull(Assert.java:737)
at org.junit.Assert.assertNull(Assert.java:747)
at hms.vnfm.lcm.service.VnfInstancesServiceTest.testCreateVnfInstanceWithNullFields(VnfInstancesServiceTest.java:75)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)

可能是什么问题?

【问题讨论】:

【参考方案1】:

添加后可以解决问题

@Transactional

我的测试方法也

【讨论】:

【参考方案2】:

当您使用 postman 调用其余 API 时,它可以工作,因为 Spring Boot 提供了一个名为 OpenSessionInViewFilter 的功能,它为您的 HTTP 请求的当前会话打开一个休眠会话。当你通过测试方法直接调用服务方法而不被@Transactional注解时,由于没有打开休眠会话,因此延迟获取不起作用。

【讨论】:

以上是关于Java Hibernate LazyInitializationException 仅在仅使用 JUnit 运行时出现的主要内容,如果未能解决你的问题,请参考以下文章

Java之旅hibernate——第一个hibernate的样例

类型-hibernate与java类型

Java面试题:Hibernate的二级缓存与Hibernate多表查询

java.lang.NoSuchMethodError: org.hibernate.cfg.Configuration.addAnnotatedClass

java反射机制动态获取hibernate懒加载对象

Hibernate 3 与 Java 1.6 兼容吗?