java - 当数据正确显示时,为什么我在这个 Spring MVC Web 应用程序中得到一个 Hibernate LazyInitializationException?

标签 java hibernate spring web-applications netbeans

我正在尝试使用 Spring MVC 创建一个 Web 应用程序,并将 Hibernate 作为其 ORM 层。但是,由于我对这两个框架都没有经验,所以我很苦恼。

以下代码将正确显示我正在查找的所有记录,但仍会在我的日志中抛出堆栈跟踪。我很难找到有关集成 Hibernate 和 SpringMVC 的完整文档(我查看了 springsource.org 并阅读了互联网上的各种文章)。谁能指出我在这里做错了什么?

请注意,我花了一些时间试图在互联网上找到答案,包括查看 this所以问题。不幸的是,这没有帮助。

我还应该注意到,这个应用程序的 ORM 部分已经在一个独立的 Java 应用程序中使用和测试,没有任何问题。所以我相信 Spring MVC 和 Hibernate 的集成导致了这个问题。

这是著名的延迟初始化问题的堆栈跟踪(截断);

2009-03-10 12:14:50,353 [http-8084-6] ERROR org.hibernate.LazyInitializationException.<init>(LazyInitializationException.java:19) - could not initialize proxy - no Session
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:57)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)
    at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:150)
    at com.generic.orm.generated.SearchRule$$EnhancerByCGLIB$$92abaed6.toString(<generated>)
    at java.lang.String.valueOf(String.java:2827)
    at java.lang.StringBuffer.append(StringBuffer.java:219)
    at org.apache.commons.lang.builder.ToStringStyle.appendDetail(ToStringStyle.java:578)
    at org.apache.commons.lang.builder.ToStringStyle.appendInternal(ToStringStyle.java:542)
    at org.apache.commons.lang.builder.ToStringStyle.append(ToStringStyle.java:428)
    at org.apache.commons.lang.builder.ToStringBuilder.append(ToStringBuilder.java:840)
    at org.apache.commons.lang.builder.ReflectionToStringBuilder.appendFieldsIn(ReflectionToStringBuilder.java:606)
.....

这是来 self 的网页 Controller 的代码;

private List<Report> getReports() {
    Session session = HibernateUtil.getSessionFactory().getCurrentSession();
    session.beginTransaction();

    List<Report> reports = session.createCriteria(Report.class).list();
    Hibernate.initialize(reports);

    session.getTransaction().commit();
    return reports;
}

在网页上使用这个显示html;

<table border="1">
    <c:forEach items="${model.reports}" var="report">
        <tr>
            <td><c:out value="${report.id}"/></td>
            <td><c:out value="${report.username}"/></td>
            <td><c:out value="${report.thresholdMet}"/></td>
            <td><c:out value="${report.results}"/></td>
            <td><c:out value="${report.searchRule.name}"/></td>
            <td><c:out value="${report.uuid}"/></td>
        </tr>
    </c:forEach>
</table>

注意:我添加了 report.searchRule.name 以测试是否可以获取报告对象中的对象。显示正常。

在我的 applicationContext.xml 中;

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="configLocation">
        <value>classpath:hibernate.cfg.xml</value>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">${hibernate.dialect}</prop>
        </props>
    </property>
</bean>

这里是 ORM 映射,以防万一;

hibernate.cfg.xml(根据要求)

<hibernate-configuration>
  <session-factory>
    <property name="hibernate.connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
    <property name="hibernate.connection.url">jdbc:sqlserver://<removed></property>
    <property name="hibernate.connection.username"><removed></property>
    <property name="hibernate.connection.password"><removed></property>
    <property name="hibernate.current_session_context_class">thread</property>
    <property name="hibernate.show_sql">false</property>
    <mapping resource="com/generic/orm/generated/Report.hbm.xml"/>
    <mapping resource="com/generic/orm/generated/FieldRule.hbm.xml"/>
    <mapping resource="com/generic/orm/generated/Reconciliation.hbm.xml"/>
    <mapping resource="com/generic/orm/generated/SearchRule.hbm.xml"/>
    <mapping resource="com/generic/orm/generated/IndexTemplate.hbm.xml"/>
    <mapping resource="com/generic/orm/generated/Field.hbm.xml"/>
    <mapping resource="com/generic/orm/generated/ErrorCode.hbm.xml"/>
  </session-factory>
</hibernate-configuration>

来自report.hbm.xml

<hibernate-mapping>
    <class name="com.generic.orm.generated.Report" table="Report" schema="dbo" catalog="CoolRecon">
        <id name="id" type="int">
            <column name="ID" />
            <generator class="native" />
        </id>
        <timestamp name="timeStamp" column="TimeStamp" />
        <many-to-one name="searchRule" class="com.generic.orm.generated.SearchRule" fetch="select">
            <column name="SearchRuleName" length="50" not-null="true" />
        </many-to-one>
        <many-to-one name="errorCode" class="com.generic.orm.generated.ErrorCode" fetch="select">
            <column name="ErrorCodeId" />
        </many-to-one>
        <many-to-one name="reconciliation" class="com.generic.orm.generated.Reconciliation" fetch="select">
            <column name="ReconciliationName" length="100" />
        </many-to-one>
        <property name="username" type="string">
            <column name="Username" length="50" />
        </property>
        <property name="supersheetDate" type="timestamp">
            <column name="SupersheetDate" length="23" not-null="true" />
        </property>
        <property name="milliSecondsTaken" type="long">
            <column name="MilliSecondsTaken" not-null="true" />
        </property>
        <property name="thresholdMet" type="boolean">
            <column name="ThresholdMet" not-null="true" />
        </property>
        <property name="results" type="int">
            <column name="Results" not-null="true" />
        </property>
        <property name="exception" type="string">
            <column name="Exception" length="750" />
        </property>
        <property name="uuid" type="string">
            <column name="UUID" length="36" not-null="true" />
        </property>
    </class>
</hibernate-mapping>

最佳答案

我刚刚经历了这个 LazyInitialization 马拉松。

核心问题是您试图在 Session 的生命周期之外访问 hibernate 管理的实体。 ,即在 Spring MVC 的 web View 中。就我而言,这是一个 List<> @OneToMany关联,默认是延迟加载的。

有几种不同的方法——Mark 提到了一种方法,您可以在其中对惰性关联进行“虚拟”迭代。您还可以通过配置(类范围)(在 JPA 中为 @Fetch(value = FetchType.EAGER))或更具体地通过 HQL 强制预加载。但这将证明更多problematic if your lazy associations are Lists .

我找到的最干净的解决方案是使用 Spring 的 OpenEntityManagerInViewFilter (有一个 OpenSessionInViewFilter 用于 Hibernate)—— 一个简单的 servlet 过滤器,您可以放入 web.xml (在其他 servlet 过滤器之前),Spring 将自动创建一个线程安全、事务感知的 Session 每个 HTTP 请求。没有了LazyInitializationException !

关于java - 当数据正确显示时,为什么我在这个 Spring MVC Web 应用程序中得到一个 Hibernate LazyInitializationException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/631695/

相关文章:

java - hibernate 映射中的另一个重复列

JavaCV:如何获取描述符的二进制字符串

java - 如何设置tomcat在 Debug模式下工作?

java - 使用 Hibernate Schema Updater 创建表时出错

spring - 将自定义 UserDetailsS​​ervice 添加到 Spring Security OAuth2 应用程序

html - Spring Thymeleaf 如何使用 select 和 option html 标签在数据库中保存特定值

java - GWT,Smart GWT,GWT-ext对比

java - Java 代码中是否可以从 MySQL 客户端运行大权限 SQL?

java - Apache Thrift。生成后方法返回类型已更改

java - byte[] PostgreSQL 中的数据