spring - Spring MVC + Hibernate : could not initialize proxy - no Session

标签 spring hibernate spring-mvc

注意:有关如何解决此问题的示例,请参阅我对这个问题的答案。

我的Spring MVC 4 + Hibernate 4项目中出现以下异常:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.mysite.Company.acknowledgements, could not initialize proxy - no Session



在阅读了有关此问题的许多其他问题之后,我了解了为什么会发生此异常,但是我不确定如何以一种好的方式来解决它。我正在执行以下操作:
  • 我的Spring MVC Controller 调用服务
  • 中的方法
  • 服务方法调用DAO类
  • 中的方法
  • DAO类中的方法通过Hibernate获取实体对象,并将其返回给调用服务
  • 服务将获取的对象返回给 Controller
  • Controller 将对象传递给 View (JSP)
  • 该 View 尝试对延迟加载(因此是代理对象)的多对多关联进行迭代
  • 引发异常,因为此时 session 已关闭,并且代理无法加载关联的数据

  • 我以前使用过PHP和doctrine2,这种处理方式没有引起任何问题。我正在尝试找出解决此问题的最佳方法,因为到目前为止我发现的解决方案似乎并不那么出色:
  • 紧急加载关联,可能会加载很多不必要的数据
  • 调用Hibernate.initialize(myObject.getAssociation());-这意味着我必须遍历关联以对其进行初始化(我想),而事实是我必须这样做,这使得延迟加载变得不太整齐
  • 使用Spring过滤器使 session 在 View 中保持打开状态,但是我怀疑这是一件好事吗?

  • 我尝试在服务中使用@Transactional,但没有运气。这是有道理的,因为在我的服务方法返回后,我试图访问尚未加载的数据。理想情况下,我希望能够从我的观点访问任何关联。我猜想在服务中初始化关联的缺点是必须明确定义所需的数据,但这取决于使用服务的上下文( Controller )。我不确定是否可以在我的 Controller 中执行此操作而不丢失DBAL层提供的抽象。我希望这是有道理的。无论哪种方式,如果我不必总是显式定义我想对 View 可用的数据,那将是很棒的,而只需让 View 来做就可以了。如果那不可能,那么我只是在寻找最优雅的解决方案。

    下面是我的代码。

    查看
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    
    <h1><c:out value="${company.name}" /> (ID: <c:out value="${company.id}" />)</h1>
    
    <c:forEach var="acknowledgement" items="${company.acknowledgements}">
        <p><c:out value="${acknowledgement.name}" /></p>
    </c:forEach>
    

    Controller
    @Controller
    public class ProfileController {
        @Autowired
        private CompanyService companyService;
    
        @RequestMapping("/profile/view/{id}")
        public String view(Model model, @PathVariable int id) {
            Company company = this.companyService.get(id);
            model.addAttribute("company", company);
    
            return "viewCompanyProfile";
        }
    }
    

    服务
    @Service
    public class CompanyServiceImpl implements CompanyService {
        @Autowired
        private CompanyDao companyDao;
    
        @Override
        public Company get(int id) {
            return this.companyDao.get(id);
        }
    }
    

    DAO
    @Repository
    @Transactional
    public class CompanyDaoImpl implements CompanyDao {
        @Autowired
        private SessionFactory sessionFactory;
    
        @Override
        public Company get(int id) {
            return (Company) this.sessionFactory.getCurrentSession().get(Company.class, id);
        }
    }
    

    公司实体
    @Entity
    @Table(name = "company")
    public class Company {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private int id;
    
        // Other fields here
    
        @ManyToMany
        @JoinTable(name = "company_acknowledgement", joinColumns = @JoinColumn(name = "company_id"), inverseJoinColumns = @JoinColumn(name = "acknowledgement_id"))
        private Set<Acknowledgement> acknowledgements;
    
        public Set<Acknowledgement> getAcknowledgements() {
            return acknowledgements;
        }
    
        public void setAcknowledgements(Set<Acknowledgement> acknowledgements) {
            this.acknowledgements = acknowledgements;
        }
    
        // Other getters and setters here
    }
    

    确认实体
    @Entity
    public class Acknowledgement {
        @Id
        private int id;
    
        // Other fields + getters and setters here
    
    }
    

    mvc-dispatcher-servlet.xml(一部分)
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <property name="packagesToScan">
                <list>
                    <value>com.mysite.company.entity</value>
                </list>
            </property>
            <property name="hibernateProperties">
                <props>
                    <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</prop>
                </props>
            </property>
        </bean>
    
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource" />
        </bean>
    
        <tx:annotation-driven />
    

    提前致谢!

    最佳答案

    最简单,最透明的解决方案是OSIV模式。如您所知,在此站点上和其他站点上都有关于此(反)模式以及替代方案的大量讨论,因此无需再次讨论。例如:

    Why is Hibernate Open Session in View considered a bad practice?

    但是,在我看来,并不是所有对OSIV的批评都是完全准确的(例如,在呈现 View 之前,事务将不会提交?是吗?如果您使用的是Spring实现,则为https://stackoverflow.com/a/10664815/1356423)

    另外,请注意,JPA 2.1引入了“提取图”的概念,该概念使您可以更好地控制加载的内容。我还没有尝试过,但是也许这终于可以解决这个长期存在的问题了!

    http://www.thoughts-on-java.org/2014/03/jpa-21-entity-graph-part-1-named-entity.html

    关于spring - Spring MVC + Hibernate : could not initialize proxy - no Session,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27299235/

    相关文章:

    java - Spring Reactor 线程模型

    java - 未能延迟初始化角色集合 :

    java - 如何使用注释在 Spring 中加载系统属性?

    java - Spring 配置文件 : Which <beans> element should be parsed?

    mysql - 如何配置一个spring+hibernate+mysql项目?

    java - css文件不适用于我的jsp(maven/spring/hibernate元素)

    java - 没有@Entity的 hibernate 存储库

    java - 玩法 2 - 默认 ebeanServer 尚未定义

    java - Web 应用程序中的 Spring beans 作用域。最佳实践

    Spring Hibernate Lazy Fetch 集合事务不起作用