`

通过Spring管理hibernate session来解决lazy-load的问题

阅读更多

学习Spring的事务还要源于我在开发中遇到的困难。我的网站Server端是基于S2SH的。问题是这样的:

 

在Service层我有一个service,部分代码如下:

 

 

@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {

	private static String getUserByNameHQL = "from User as user where user.userName = ?";

	private static String deleteByIDHQL = "delete from User as user where user.id=?";

	private static String findLogonInfoHQL = "from LogonValidationInfo as info where info.userName=? and info.sessionid=?";

	private static String deleteLogonInfoHQL = "delete from LogonValidationInfo as info where info.userName=? and info.sessionid=?";

	private HibernateDaoSupport dao;

	public HibernateDaoSupport getDao() {
		return dao;
	}

	@Autowired
	public void setDao(HibernateDaoSupport dao) {
		this.dao = dao;
	}

	
	public User getUserByName(String userName ) {
		User user = null;
		List results = this.dao.getHibernateTemplate().find(getUserByNameHQL,
				userName);
		if (results != null && !results.isEmpty()) {
			user = (User) results.get(0);
		}
		
		return user;
	}

 

 

Dao的继承的Spring提供的HibernateDaoSupport,并通过Spring标注注入到UserService里,dao的代码如下

 

 

@Repository
public class HibernateGenericDaoImpl extends HibernateDaoSupport{
    @Autowired  
    public void setSessionFactoryOverride(SessionFactory sessionFactory)   
    {   
  
        super.setSessionFactory(sessionFactory);   
    }

}

 

实体类User, Node存在一对多的双向关联关系,实体类比较通俗就不贴出来了,hbm文件如下,User对象通过自己的Set<TimelineNode>映射了一组Node类型。

 

 

	<class name="User" table="user">
		<id name="id" column="uid">
			<generator class="increment" />
		</id>
		<property name="firstName" column="firstname"/>
		<property name="lastName" column="lastname"/>
		<property name="userPwd" column="password"/>
		<property name="userName" column="username"/>
		 <set name="nodes" inverse="true" cascade="all" lazy="true" 
			table="timelinenode">
                <key column="user_id" not-null="true"></key>
                <one-to-many class="TimeLineNode"/>
          </set>
	</class>

  

	<class name="TimeLineNode" table="timelinenode">		
		<id name="ID" column="id">
			<generator class="increment" />
		</id>
		<property name="startDate" type="date">
			<column name="starttime" sql-type="datetime" />
		</property>
		<property name="endDate" type="date">
			<column name="endtime" sql-type="datetime" />
		</property>
		<property name="headline" type="text" column="header">
		</property>
		<property name="text" type="text" column="article">
		<property name="isStartNode" column="titleSlide" />
		<property name="tags" />
		<property name="media" />
		<property name="credit" />
		<property name="caption" />
		<property name="bgrImg" column="bgrimg" />
		<many-to-one name="author" class="User" lazy="false"
			column="user_id" cascade="all">
		</many-to-one>
	</class>

 

调用过程是UserAction->UserService->Dao

 

UserAction的入口方法:</property>public String login() {

                  ...............

		User user = null;
		try {
			user = userService.getUserByName(uname); 
                        Set nodes=user.getNodes(); //lazy load ,sesseion closed exception will throw out here
                 ..................

}

  红字的那一行,因为在hibernate映射文件里采用了lazy="true"的加载方法,user.getNodes()的时候会从新去数据库中得数据,可是这个时候user对象所处的session已经关闭掉了。会抛出一个异常

org.hibernate.LazyInitializationException: could not initialize proxy - no Session.

解决这个问题有如下几个方案:

 

一.设置第一个映射文件中lazy="false",采用非延迟加载,不过这样做挺扯淡,我本来就为了系统性能提升才采用的延迟加载策略,这么一改我不就白干了,所以果断否掉,这条也作为解决方案的其中一个的原因则是如果系统性能要求没那么高或者一次性加载的东西并不太占用内存,可以考虑采用这样的方式。

 

二.Spring提供的方案OpenSessionInView.

  Spring提供了OpenSessionInViewInterceptor和OpenSessionInViewFilter这两种方式实现这个解决方案。

  这两个主要都是在一个url请求到来的时候为程序打开一个hibernate session,然后请求结束的时候关闭这个session,我没有采用这种解决方案,因为

1.Open Session In View的解决方案存在性能上的争论。

2.我的lazy load发生在action层(这里要讲一下,其实执行lazy load的这段代码完全可以放到service层,只不过这个逻业务逻辑不是很复杂,加上本人手懒,就没有抽到service层里,如果要加入事务的话,最好还是要先抽一下这块代码),不应该讲其范围扩大到整个request范围,还要涉及到request的跳转问题(这个我也不是很确定,不过redirect的话该session应该是失效的,未经测试纯属猜测)。

 

 

三.采用hibernate的API手动解析目标代理。通过查阅Hibernate的API,发现了下面这个东东:

 Hibernate的静态方法isInitialized

public static boolean isInitialized(Object proxy)

  

描述如下:

Check if the proxy or persistent collection is initialized.

 

Parameters:
proxy - a persistable object, proxy, persistent collection or null
Returns:
true if the argument is already initialized, or is not a proxy or collection

 

OK,在我这个例子里,参数proxy代表的即是user.getNodes();

修改了一下userService.getUserByName方法:

public User getUserByName(String userName ,boolean initChildren) {		
		User user = null;
		List results = this.dao.getHibernateTemplate().find(getUserByNameHQL,
				userName);
		if (results != null && !results.isEmpty()) {
			user = (User) results.get(0);
		}
		if(user!=null && initChildren){
			initializeObject(user.getNodes());
		}
		return user;
	}

 

initializeObject方法如下:

 

public void initializeObject(Object proxy) {
			Hibernate.initialize(proxy);  //To solve the lazy-load problem
	}

 

测试,搞定。这个困扰了我几天的问题终于解决了。

分享到:
评论
1 楼 Monkey-_-DLuffy 2015-04-22  
Hibernate.initialize(proxy)  ===lazy="false"

相关推荐

    Spring 和Hibernate 整合笔记和jar包

    - **SessionFactory的获取**:Spring通过HibernateTemplate或SessionFactoryBean来创建SessionFactory,进一步管理Hibernate的Session。 - **DAO(Data Access Object)层**:Spring的DAO支持类如...

    SSH(struts+spring+hibernate)面试题总结

    Hibernate支持多种关系映射,如一对一(OneToOne),一对多(OneToMany),多对一(ManyToOne),多对多(ManyToMany),通过注解或XML配置来声明这些关系。 在面试中,对于SSH的掌握不仅要求理解这些基本概念,还需要能够...

    struts+spring+hibernate面试题

    在Java Web开发中,Struts、Spring和Hibernate是最常见的三大框架,它们...以上就是关于Struts、Spring和Hibernate面试题的详细解析,涵盖了这三大框架的关键概念和使用技巧,对于理解和解答相关面试问题非常有帮助。

    Hibernate框架搭建及数据库相关操作

    1. **查询**:使用 `session.get()` 或 `session.load()` 获取单个对象,`session.createQuery()` 或 `session.createCriteria()` 用于执行 HQL(Hibernate Query Language)查询。 2. **更新**:通过 `session....

    解决Lazy最有效的方法

    `ContextLoaderServlet`是Spring框架用于加载和管理应用上下文的Servlet,通过设置`load-on-startup`属性,可以控制其加载时机,从而影响整个应用的启动性能和资源消耗。 ### 三、Hibernate与Lazy Loading 除了...

    hibernate.jar包

    Spring通过AOP(面向切面编程)实现事务管理,使得SSH框架的分工明确,协同高效。 5. Hibernate的性能优化: - 第二级缓存:通过插件如Ehcache,缓存对象,减少对数据库的访问。 - 分页查询:避免一次性加载大量...

    有关hibernate、spring、struts的面试题

    Spring 通常与Hibernate一起使用,负责管理Hibernate的SessionFactory和Session,以及整个应用的事务。Spring 也提供了ModelAndView、DispatcherServlet等用于MVC模式的组件。 1. **依赖注入**:Spring 通过XML配置...

    hibernate讲义

    - 加载和查询:`session.get()` 用于按主键加载对象,`session.load()` 返回代理对象,`session.createQuery()` 和 `session.createCriteria()` 用于构建 HQL(Hibernate 查询语言)或 Criteria 查询。 5. **事务...

    ssh(structs,spring,hibernate)框架中的上传下载

     以上是Spring+Hibernate将文件二进制数据持久化到数据库的解决方案,而Struts通过将表单中file类型的组件映射为ActionForm中类型为org.apache.struts.upload. FormFile的属性来获取表单提交的文件数据。  工程...

    hibernate-release-4.3.4.Final

    声明式事务管理则可以通过Spring等框架配置,简化事务处理代码。 七、高级特性 1. 支持关联映射:包括一对一、一对多、多对一、多对多等关系映射。 2. 集合映射:允许对象集合与数据库表的列进行映射。 3. 延迟...

    spring_精简教程

    - **Spring与SSH整合实例**:通过绘制SSH(Spring、Struts2、Hibernate)整合实例的架构图,清晰地展示了客户端请求经过的各个层次,包括核心过滤器、Action、Service层、DAO层以及Hibernate的数据库操作过程。...

    hibernate3.5.6开发包

    Hibernate 是一个流行的开源对象关系映射(ORM)框架,它为Java开发者提供了一种方便的方式来管理数据库操作。这个开发包包含了Hibernate 3.5.6 Final版本的所有必要组件,包括核心库、文档和示例代码,使得开发者...

    HIBERNATE

    - Hibernate 广泛应用于Web应用,如Spring Boot集成Hibernate,通过Spring的声明式事务管理简化事务处理。 通过深入学习和实践本教程中的源代码,你将能够熟练掌握Hibernate的基本操作,为开发J2EE应用打下坚实的...

    hibernate的延迟检索在轻量级J2EE框架中的应用

    - **Spring集成**:Spring可以很好地集成Hibernate,通过Spring的事务管理器,可以更好地控制事务边界,同时利用Spring的AOP特性,可以更加灵活地管理延迟加载的行为。 - **业务逻辑优化**:在业务逻辑层,合理使用...

    Hibernate技术手册.chm(台湾写的)

    - Spring整合Hibernate时的声明式事务管理。 6. **查询语言HQL**: - HQL简介:面向对象的查询语言,类似于SQL,但操作的是对象而非表。 - HQL的基本语法:SELECT、FROM、WHERE、GROUP BY、ORDER BY等子句。 - ...

    hibernate4.2.1

    3. **实体管理**:Hibernate通过实体类来映射数据库表,实体类上使用注解如`@Entity`、`@Table`、`@Id`等来定义数据库映射关系。实体之间的关系也可以通过注解如`@OneToOne`、`@OneToMany`、`@ManyToOne`、`@...

    Hibernate_DEV_GUIDE

    Hibernate 与Spring的整合,可以利用Spring的IoC(控制反转)和AOP特性,进一步简化持久层的代码,实现声明式事务,并将Hibernate的Session管理纳入Spring的管理范围。 10. **最佳实践** 在实际开发中,应遵循...

    Hibernate经典入门教程

    编程式事务管理使用Transaction接口,而声明式事务管理常通过Spring框架实现。 八、性能优化 1. 第二级缓存:提高数据访问速度,通过配置Cache Provider如Ehcache。 2. 配置批处理:设置hibernate.jdbc.batch_size...

    hibernate大纲

    4. **加载(Load)**:通过 `session.load()` 直接获取对象,基于主键。 5. **检索(Get)**:使用 `session.get()` 根据主键获取对象,或使用 `session.createQuery()` 或 `session.createCriteria()` 进行更复杂的...

Global site tag (gtag.js) - Google Analytics