尽管在 @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。你当然也可以禁用惰性初始化