尽管在 @Transactional 中并且没有分离的实体,但仍获取 LazyInitializationException
Getting LazyInitializationException despite being in @Transactional and having no detached entities
我正在使用 Spring 3.2.11.RELEASE、JPA 2.1、Hibernate 4.3.6.Final 和 MySQL 5.5.37。我在 JUnit 测试中遇到以下错误
testSendValidAssignment(org.mainco.subco.thirdParty.service.ThirdPartyServiceIT) Time elapsed: 13.366 sec <<< ERROR!
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: org.mainco.subco.lessonplan.domain.LessonPlan.classrooms, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:214)
at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:155)
at org.hibernate.collection.internal.PersistentBag.size(PersistentBag.java:278)
at org.mainco.subco.ThirdParty.service.ThirdPartyServiceIT.testSendValidAssignment(ThirdPartyServiceIT.java:102)
但是,我不知道这条错误消息应该归咎于哪一行。在我的方法中我有
@Service
@Transactional
public class MyServiceImpl implements MyService
{
....
@Override
public void sendAssignment(final String assignmentId)
{
final Assignment assignment = m_lessonPlanDao.getAssignment(assignmentId);
if (processData(assignment))
{
// Gather the students who have been assigned this assignment
final List<Classroom> classes = lessonPlan.getClassrooms();
System.out.println("got " + classes.size() + " classes.");
// Send one request for each class assignment
for (final Classroom classroom : classes)
{
final List<User> classStudents = m_classroomSvc.findClassStudents(classroom.getId());
System.out.println("got " + classStudents.size() + " students.");
和 System.out 行都打印数字。方法中没有对这个延迟加载集合的其他引用,所以我不知道还有什么要检查我的数据。任何建议表示赞赏。
您的服务方法是事务性的,但您的整个测试方法不是。元素的大小检查是在 JUnit 测试的断言语句中执行的,并且是在服务的事务范围之外完成的,因此会导致延迟初始化异常。您可以选择三种方式
- 你可以尝试在你的 dao 方法中调用
size()
方法来制作
size()
方法的外部调用是安全的。
- 你可以强制使用你的方法的用户
打开事务(记录哪些对象被分离并使其成为
contract/or 使用臭名昭著的
open session in view
模式)
- 您可以创建 DTO 层和 return 大小作为 DTO 的一部分
三种解决方案各有利弊:
第一个解决方案对于代码的支持者来说看起来很奇怪,因为他们会发现您调用 getter 没有明显的原因 - 它需要评论。
第二个让界面用户的生活更加艰难
第三个违反DRY原则
p.s。你当然也可以禁用惰性初始化
我正在使用 Spring 3.2.11.RELEASE、JPA 2.1、Hibernate 4.3.6.Final 和 MySQL 5.5.37。我在 JUnit 测试中遇到以下错误
testSendValidAssignment(org.mainco.subco.thirdParty.service.ThirdPartyServiceIT) Time elapsed: 13.366 sec <<< ERROR!
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: org.mainco.subco.lessonplan.domain.LessonPlan.classrooms, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:214)
at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:155)
at org.hibernate.collection.internal.PersistentBag.size(PersistentBag.java:278)
at org.mainco.subco.ThirdParty.service.ThirdPartyServiceIT.testSendValidAssignment(ThirdPartyServiceIT.java:102)
但是,我不知道这条错误消息应该归咎于哪一行。在我的方法中我有
@Service
@Transactional
public class MyServiceImpl implements MyService
{
....
@Override
public void sendAssignment(final String assignmentId)
{
final Assignment assignment = m_lessonPlanDao.getAssignment(assignmentId);
if (processData(assignment))
{
// Gather the students who have been assigned this assignment
final List<Classroom> classes = lessonPlan.getClassrooms();
System.out.println("got " + classes.size() + " classes.");
// Send one request for each class assignment
for (final Classroom classroom : classes)
{
final List<User> classStudents = m_classroomSvc.findClassStudents(classroom.getId());
System.out.println("got " + classStudents.size() + " students.");
和 System.out 行都打印数字。方法中没有对这个延迟加载集合的其他引用,所以我不知道还有什么要检查我的数据。任何建议表示赞赏。
您的服务方法是事务性的,但您的整个测试方法不是。元素的大小检查是在 JUnit 测试的断言语句中执行的,并且是在服务的事务范围之外完成的,因此会导致延迟初始化异常。您可以选择三种方式
- 你可以尝试在你的 dao 方法中调用
size()
方法来制作size()
方法的外部调用是安全的。 - 你可以强制使用你的方法的用户
打开事务(记录哪些对象被分离并使其成为
contract/or 使用臭名昭著的
open session in view
模式) - 您可以创建 DTO 层和 return 大小作为 DTO 的一部分
三种解决方案各有利弊:
第一个解决方案对于代码的支持者来说看起来很奇怪,因为他们会发现您调用 getter 没有明显的原因 - 它需要评论。
第二个让界面用户的生活更加艰难
第三个违反DRY原则
p.s。你当然也可以禁用惰性初始化