如何在Spring MVC中使用延迟加载

4
如何在Spring MVC中使用懒加载?我目前正在使用急切加载,但这使我的应用程序变得更慢。 以下是我的域的一部分:
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "NEWS_TAG", joinColumns = @JoinColumn(name = "NEWS_ID"), inverseJoinColumns = @JoinColumn(name = "TAG_ID"))
private List<Tags> tags = new ArrayList<Tags>();

public List<Tags> getTags() {
    return this.tags;
}

And dao:

public List<News> getSomeNews(long b, long hm) {

    List<News> news = (List<News>) sessionFactory
            .getCurrentSession()
            .createQuery(
                    "from News WHERE title!='About' ORDER BY publish_time")
            .setMaxResults((int) hm).setFirstResult((int) b).list();
    return news;
}

Servlet上下文:

    <context:annotation-config />

    <context:component-scan base-package="net.babobka.blog" />



    <import resource="../../db/db-config.xml" />

    <bean id="urlForwardController"
        class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />

    <bean id="tilesConfigurer"
        class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
        <property name="definitions">
            <list>
                <value>/WEB-INF/tiles.xml</value>
            </list>
        </property>
    </bean>

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.tiles2.TilesView" />
    </bean>

</beans>

数据库配置:

<bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
        p:location="/WEB-INF/db/jdbc.properties" />

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
        p:url="${jdbc.databaseurl}" p:username="${jdbc.username}" p:password="${jdbc.password}" />

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation">
            <value>/WEB-INF/db/hibernate.cfg.xml</value>
        </property>
        <property name="configurationClass">
            <value>org.hibernate.cfg.AnnotationConfiguration</value>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${jdbc.dialect}</prop>
                <prop key="hibernate.show_sql">${jdbc.show_sql}</prop>
            </props>
        </property>
    </bean>

    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <tx:annotation-driven />

</beans>

Web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <!-- The definition of the Root Spring Container shared by all Servlets 
        and Filters -->
    <context-param>
        <param-name>contextConfigLocation</param-name>

        <param-value>
        /WEB-INF/spring/root-context.xml
        /WEB-INF/spring/application-security.xml
        </param-value>
    </context-param>



    <!-- Creates the Spring Container shared by all Servlets and Filters -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>



    <!-- Processes application requests -->
    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>*.gif</url-pattern>
    </servlet-mapping>
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>hibernateFilterChain</filter-name>
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hibernateFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>




</web-app>

我该怎么做来解决我的问题?

2个回答

6
您可以使用 OpenSessionInViewFilter 避免 hibernate session 关闭。将其添加到 web.xml 中:
  <filter>
    <filter-name>hibernateFilterChain</filter-name>
    <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>hibernateFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

更多信息请参见:OpenSessionInViewFilter

同时移除fetch = FetchType.EAGER@ManyToMany 默认为LAZY。


未定义名称为'sessionFactory'的bean。 - babobka
@Autowired private SessionFactory sessionFactory; 在 DAOImpl 中 - babobka
看这个问题。我添加了这个。3.6.9.Final - 版本。 - babobka
严重: 启动过滤器hibernateFilterChain时出现异常 java.lang.ClassNotFoundException: org.springframework.orm.hibernate3.support.OpenSessionInViewFilter - babobka
我有这个。它不正确吗?<dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${org.springframework-version}</version> <type>jar</type> </dependency> - babobka
显示剩余17条评论

1
将您的注释更改为(fetch = FetchType.LAZY)。请注意,如果您将结果传递给事务外部的某些代码(例如视图模板),如果外部代码需要的关联对象尚未加载,则可能会遇到错误。

不加 FetchType.LAZY 我会遇到一些关于 session 或其他方面的错误。 - babobka
你的评论不够清晰。你是说如果你改为LAZY,就会开始出现错误吗?那些错误是在事务结束后尝试访问未加载关联实体的结果吗? - chrylis -cautiouslyoptimistic-
"Session was closed" 意味着您的代码尝试从“tags”字段中读取信息,但该字段尚未加载,并且无法加载它,因为事务(会话)已结束。在事务结束后,您无法惰性加载更多数据;您必须急切地加载,特别是加载将要使用的字段,或者在事务内执行给出错误的代码。 - chrylis -cautiouslyoptimistic-
不是特别的。只有在通常不访问字段且加载成本高昂时才应使用惰性加载,这意味着如果您稍后确实需要该字段,则ORM系统必须返回数据库以查找它。您可以选择不使用惰性加载,强制ORM加载您知道将要使用的特定字段,或者在事务内运行所有内容。如果您预计通常会使用“标签”,则使用惰性加载只会通过使读取“标签”稍后变慢来加快初始加载。 - chrylis -cautiouslyoptimistic-
好的。我不想再使用LAZY了。如何使用EAGER呢?我的意思是获取标签的字段,而不绑定像新闻等字段。请给我展示一些代码。这比语言更能说明问题。 - babobka
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接