`

原:hibernate延迟加载延伸的一个问题

 
阅读更多

hibernate配置延迟加载报:failed to lazily initialize a collection of role: com.ln.jtf.biz.dal.dao.pojos.Customer.cusaccounts, no session or session was closed。原因是web上get子表时session已经关闭。针对这个问题spring提供了解决方案,有两种方式:

 

一种是过滤器:OpenSessionInViewFilter,在web.xml文件中增加配置如下:

 

	<filter>
		<filter-name>hibernateFilter</filter-name>
		<filter-class>
	org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
		</filter-class>
	</filter>

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

看一下代码实现:

 

protected void doFilterInternal(
			HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		SessionFactory sessionFactory = lookupSessionFactory(request);
		boolean participate = false;

		if (isSingleSession()) {
			// single session mode
			if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
				// Do not modify the Session: just set the participate flag.
				participate = true;
			}
			else {
				logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
				Session session = getSession(sessionFactory);
				TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
			}
		}
		else {
			// deferred close mode
			if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {
				// Do not modify deferred close: just set the participate flag.
				participate = true;
			}
			else {
				SessionFactoryUtils.initDeferredClose(sessionFactory);
			}
		}

		//.....
	}

 通过ROOT WebApplicationContext已获取一个普通spring bean的方式来获取SessionFactory 

 

 

protected SessionFactory lookupSessionFactory() {
		if (logger.isDebugEnabled()) {
			logger.debug("Using SessionFactory '" + getSessionFactoryBeanName() + "' for OpenSessionInViewFilter");
		}
		WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
		return wac.getBean(getSessionFactoryBeanName(), SessionFactory.class);
	}

 

 再看如何获取到WebApplicationContext:

 

public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) {
		Assert.notNull(sc, "ServletContext must not be null");
		Object attr = sc.getAttribute(attrName);
		if (attr == null) {
			return null;
		}
		if (attr instanceof RuntimeException) {
			throw (RuntimeException) attr;
		}
		if (attr instanceof Error) {
			throw (Error) attr;
		}
		if (attr instanceof Exception) {
			throw new IllegalStateException((Exception) attr);
		}
		if (!(attr instanceof WebApplicationContext)) {
			throw new IllegalStateException("Context attribute is not of type WebApplicationContext: " + attr);
		}
		return (WebApplicationContext) attr;
	}

 

 其中attrName为:String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";

在某些配置下(?)由于根据这个attrName找不到对应的attr造成 sc.getAttribute(attrName)这个方法得到的是null,而报No WebApplicationContext found: no ContextLoaderListener registered?这个错误。

 

 

一种是配置拦截器:OpenSessionInViewInterceptor,在spring配置文件中增加如下(我使用的是Schema-based XML方式):

 

	<mvc:interceptors>
		<bean id="openSessionInViewInterceptor"
	           class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
	        <property name="sessionFactory" ref="sessionFactory"/>
	    </bean>
    </mvc:interceptors>

 这样配置之后session将会保持。

 

看一下代码实现:

 

public void preHandle(WebRequest request) throws DataAccessException {
		if ((isSingleSession() && TransactionSynchronizationManager.hasResource(getSessionFactory())) ||
		    SessionFactoryUtils.isDeferredCloseActive(getSessionFactory())) {
			// Do not modify the Session: just mark the request accordingly.
			String participateAttributeName = getParticipateAttributeName();
			Integer count = (Integer) request.getAttribute(participateAttributeName, WebRequest.SCOPE_REQUEST);
			int newCount = (count != null ? count + 1 : 1);
			request.setAttribute(getParticipateAttributeName(), newCount, WebRequest.SCOPE_REQUEST);
		}
		else {
			if (isSingleSession()) {
				// single session mode
				logger.debug("Opening single Hibernate Session in OpenSessionInViewInterceptor");
				Session session = SessionFactoryUtils.getSession(
						getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
				applyFlushMode(session, false);
				TransactionSynchronizationManager.bindResource(getSessionFactory(), new SessionHolder(session));
			}
			else {
				// deferred close mode
				SessionFactoryUtils.initDeferredClose(getSessionFactory());
			}
		}
	}

可以看到在这里spring做了判断,如果当前请求线程中没有绑定session,那么就新创建一个,并且绑定到当前线程中。特别要提一下这里是通过HibernateAccessor这个InitializingBean来获取到SessionFactory的,和过滤器的方式不同。 

 

 

 

分享到:
评论

相关推荐

    Hibernate延迟加载以及利用Spring

    - `lazy="proxy"`:表示Hibernate将为`Dept`实体创建一个代理对象,只有当真正访问到`Dept`对象的相关属性时,Hibernate才会发起数据库查询,加载实际的`Dept`对象。 - `fetch="select"`:默认值,表示在查询`Emp`时...

    hibernate 延迟加载深入剖析

    当Hibernate加载一个实体时,默认不会立即加载其关联的实体或集合属性。相反,它会创建一个代理对象来表示这些属性。当程序试图访问这些属性时,Hibernate会在后台异步加载实际的数据。 #### 三、延迟加载的具体...

    hibernate延迟加载解决

    这是因为,如果不使用延迟加载,加载一个实体可能会导致所有相关联的实体都被加载到内存中,从而严重影响性能。 **配置方式:** 要启用集合类型的延迟加载,需要在映射文件中为集合元素添加`lazy="true"`属性,...

    Hibernate 延迟加载剖析与代理模式应用

    Hibernate利用Java的动态代理机制,为延迟加载的集合属性创建了一个代理对象。当我们尝试访问`addresses`时,实际上是在调用代理对象的方法,代理对象会检测到这个访问请求,然后触发实际的数据库查询,加载关联的`...

    什么是hibernate延迟加载

    详细介绍hibernate延迟加载,对hibernate初学者有一定的帮助

    Flex 与 Hibernate 的延迟加载问题

    在开发Flex与Hibernate集成的应用时,延迟加载(Lazy Loading)是一个常见的挑战,因为Flex客户端无法直接理解和处理Hibernate的延迟加载机制。延迟加载是一种优化策略,它允许关联的对象在真正需要时才被加载,而...

    hibernate 延迟加载.docx

    当使用Hibernate的`Session.load()`方法或在映射文件中设置了`lazy="true"`时,Hibernate并不会立即从数据库中获取关联对象的所有数据,而是创建一个代理对象。这个代理对象在需要访问其属性时才会执行实际的数据库...

    Hibernate 延迟加载

    其中一个关键问题是,延迟加载机制依赖于保持Session对象处于打开状态。这对于采用DAO(Data Access Object)模式,即试图将持久层逻辑与业务逻辑完全分离的设计来说,构成了挑战。 在DAO模式下,所有数据库操作,...

    Hibernate的延迟加载

    在代码片段`(1)`中,Hibernate不会立即加载`addresses`集合,而是返回一个代理集合。当代码片段`(2)`被执行,即迭代器开始遍历集合时,Hibernate才会执行必要的数据库查询,加载关联的地址信息。 ### 总结 通过...

    Hibernate延迟加载机制.zip

    Hibernate延迟加载机制.zip

    Hibernate集合属性的延迟加载.doc

    在给定的文档中,我们看到一个例子,展示了如何在 Hibernate 中配置一个具有集合属性的实体类 `Person`,以及如何通过映射文件启用延迟加载。`Person` 类拥有一个 `Set&lt;Address&gt;` 类型的 `addresses` 属性,表示个人...

    Hibernate延迟加载介绍.doc

    Hibernate作为Java领域中的一个强大的对象关系映射框架,提供了许多优化数据库操作的策略,其中之一便是延迟加载(Lazy Loading)。延迟加载机制旨在减少不必要的性能消耗,只在真正需要数据时才执行加载操作。本文...

    hibernate延迟加载技术详细解

    - 如果没有显式设置 lazy="false",则默认情况下 Hibernate 使用 Select Fetching,这意味着对于每个主对象,Hibernate 都会发送一个 SQL 查询来加载关联对象。 - 这种方式适用于关联数据量不大,且每次查询都需要...

    Hibernate lazy延迟加载

    2. 当执行查询并返回实体时,如果关联对象标记为懒加载,Hibernate并不会立即执行SQL去获取关联数据,而是创建一个代理对象。这个代理对象会在真正访问关联属性时,通过执行额外的数据库查询来获取数据。 3. ...

    Hibernate延迟加载

    **延迟加载**(Lazy Loading)是Hibernate框架中的一个重要特性,主要用于优化数据库操作,减少不必要的数据加载,从而提升应用程序的性能。在传统的Eager Loading(急切加载)模式下,一旦加载了一个对象,与之相关的...

    【北大青鸟内部教程】jsp中关于Hibernate延时加载的问题

    3. **事务管理**:延时加载需要在一个有效的Hibernate Session内进行。在多层架构中,确保事务管理正确,尤其是在Service和DAO层之间,是确保延时加载成功的关键。 4. **N+1查询问题**:如果一个实体有多个关联属性...

Global site tag (gtag.js) - Google Analytics