`
daiyuok
  • 浏览: 25394 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

主要讨论Spring与Hibernate集成中的session问题

阅读更多

转自http://www.iteye.com/topic/733971

1.通过getSession()方法获得session进行操作

Java代码  收藏代码
  1. public   class  Test   extends  HibernateDaoSupport{  
  2.      public   void  save(User user){  
  3.         this .getSession().save(user);  
  4.      }  
  5. }    


利用这种方式获得的session在方法执行结束之后不会自动关闭连接 ,也就是说我们必须通过session.close()或者releaseSession(session)来手动进行关闭,否则会造成内存泄露或者连接耗尽等问题。手动关闭:

Java代码  收藏代码
  1. public   class  Test   extends  HibernateDaoSupport{  
  2.      public   void  save(User user){  
  3.         Session session = this .getSession();  
  4.         session.save(user);  
  5.         session.close();  
  6.         // releaseSession(session);    
  7.      }  
  8. }   


如果对上述方法进行事务控制,那么spring框架会自动为我们关闭session,此种情况下再执行上述代码,会抛出如下异常:

Java代码  收藏代码
  1.  org.springframework.orm.hibernate3.HibernateSystemException: Session is closed; nested exception is org.hibernate.SessionException: Session is closed  
  2. …  
  3. org.hibernate.SessionException: Session is closed  


提示session已经关闭。但是如果在代码中通过releaseSession(session)的方法来关闭session,则不会抛出异常。releaseSession(session)方法的代码如下:

Java代码  收藏代码
  1. protected   final   void  releaseSession(Session session) {  
  2.     SessionFactoryUtils.releaseSession(session, getSessionFactory());  
  3. }  


也就是说它是通过SessionFactoryUtils的releaseSession方法来实现的:

Java代码  收藏代码
  1. public   static   void  releaseSession(   
  2.      Session session,SessionFactory sessionFactory) {  
  3.           if  (session ==  null ) {  
  4.               return ;  
  5.           }  
  6.           // Only close non-transactional Sessions.   
  7.           if  (!isSessionTransactional(session,sessionFactory))   {  
  8.              closeSessionOrRegisterDeferredClose  (session, sessionFactory);  
  9.           }  
  10.     }  


可见它内部会先进行判断。

查看getSession()方法的源码:

Java代码  收藏代码
  1. protected   final  Session getSession()  
  2.         throws  DataAccessResourceFailureException, IllegalStateException {  
  3.   
  4.         return  getSession( this .hibernateTemplate.isAllowCreate());  
  5. }  


getSession()方法内部通过它的一个重载方法getSession(boolean allowCreate )来实现,变量allowCreate是HibernateTemplate中的变量,默认值为true,也就是创建一个新的session。如果我们调 用getSession(false)来获得session,那么必须对其进行事务控制,原因是:(spring文档)

Java代码  收藏代码
  1. protected    final   org.hibernate.Session  getSession()   
  2. throws  DataAccessResourceFailureException,   IllegalStateException    
  3.   
  4. Get a Hibernate Session, either from the current transaction or a new  one. The latter is only allowed  if  the  "allowCreate"  setting of  this  bean's HibernateTemplate is  true .   


也就是说,getSession()方法从当前事务或者一个新的事务中获得session,如果想从一个新的事务中获得 session(也就意味着当其不存在事务控制),则必须使HibernateTemplate中的allowCreate变量的值为”true”,而现 在设置allowCreate变量的值为”false”就意味着无法从新的事务中获得session,也就是只能从当前事务中获取,所以必须对当前方法进 行事务控制,否则会抛出如下异常:

Java代码  收藏代码
  1. java.lang.IllegalStateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here ...  


同时,如果对getSession()所在的方法进行事务控制,那么类似如下的代码:

Java代码  收藏代码
  1. Session session =  null ;  
  2. for ( int  m = 0 ;m< 5 ;m++){  
  3.     Admin admin = new  Admin();  
  4.     admin.setName("test" );  
  5.     admin.setPassword("098" );     
  6.     session = this .getSession();  
  7.     session.save(admin);  
  8. }  


只会打开一个session,因为事务控制必须确保是同一个连接,spring会确保在整个相关方法中只存在一个 session。Spring在方法开始时会打开一个session(即使进行事务控制的方法内部不执行数据库操作),之后在请求session时,如果 在事务中存在一个未commit的session就返回,以此确保同一个session。

2.getCurrentSession()与openSession()
getCurrentSession()与openSession()方法通过Hibernate的SessionFactory获得,两者的区别网上有很多文章已经介绍过,即:

Java代码  收藏代码
  1. ①getCurrentSession创建的session会和绑定到当前线程,而openSession不会。   
  2. ②getCurrentSession创建的线程会在事务回滚或事物提交后自动关闭,而openSession必须手动关闭  



对于getCurrentSession()方法:
        (1)其所在方法必须进行事务控制
        (2)Session在第一次被使用的时候,或者第一次调用getCurrentSession()的时候,其生命周期就开始。然后它被 Hibernate绑定到当前线程。当事务结束的时候,不管是提交还是回滚,Hibernate也会把Session从当前线程剥离,并且关闭它。假若你 再次调用getCurrentSession(),你会得到一个新的Session,并且开始一个新的工作单元。    
  
对于openSession()方法:
         这个方法一般在spring与Hibernate的集成中不直接使用,它就是打开一个session,并且这个session与上下文无关,如果对其所在 方法进行事务控制,会发现不起作用,原因就是前面提到的,事务控制必须确保是同一个连接,而openSession()打开的session与上下文无 关。这个方法与getSession(),getCurrentSession()以及getHibernateTemplate()等方法的区别在于: 后面的几个方法spring可以对其进行控制,如果对它们所在的方法进行事务控制,spring可以确保是同一个连接,而openSession()方 法,spring无法对其进行控制,所以事务也不会起作用。


3.OpenSessionInView
OpenSessionInView的主要功能是用来把一个Hibernate Session和一次完整的请求过程对应的线程相绑定。Open Session In View在request把session绑定到当前thread期间一直保持hibernate session在open状态,使session在request的整个期间都可以使用,如在View层里PO也可以lazy loading数据,如 ${ company.employees }。当View 层逻辑完成后,才会通过Filter的doFilter方法或Interceptor的postHandle方法自动关闭session。

Java代码  收藏代码
  1. public   class  Group  implements  Serializable{   
  2.     private   int  id;   
  3.     private  String name;   
  4.     private  Set users;  
  5.          ...  
  6. }  


在业务方法中加载Group对象并将其保存到HttpSession对象中

Java代码  收藏代码
  1. List groups = ht.find( "from Group" );  
  2. Group group = (Group)groups.get(0 );  
  3. HttpSession session = ServletActionContext.getRequest().getSession();  
  4. session.setAttribute("group" , group);  


注意Group采用默认的延迟加载机制,即此时返回的只是一个Group代理对象,
在jsp页面中显示group对象的users属性,如下:

Java代码  收藏代码
  1. <%    
  2.      Group group = (Group)session.getAttribute("group" );  
  3.      out.println(group.getUsers());  
  4. %>   


此时会抛出如下异常:

Java代码  收藏代码
  1. org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: entity.Group.users, no session or session was closed  


延迟加载机制使得在业务方法执行结束之后仅仅返回Group的一个代理对象,在jsp页面中使用到group对象的值时,才发出 sql语句加载,但此时session已经关闭。解决方法是采用OpenSessionInView机制,在web.xml页面中配置如下过滤器:

Java代码  收藏代码
  1. <filter>    
  2.    <filter-name>hibernateFilter</filter-name>   
  3.    <filter-class >   
  4. org.springframework.orm.hibernate3.support.OpenSessionInViewFilter  
  5.    </filter-class >    
  6. </filter>  



总结:
(1) 对于getSession(),getSession(false),getCurrentSession()以及 getHibernateTemplate()方法而言,如果对其所在方法进行事务控制,那么可以确保在整个方法中只存在一个session,无论你执行 了几次CRUD操作,并且所打开的session会在事务结束时自动关闭。
(2) 必须对getSession(false)以及getCurrentSession()所在的方法进行事务控制(原因见上述分析)
(3) 如果没有对getSession()以及getHibernateTemplate()所在方法进行事务控制,那么如果在方法中进行N次CRUD操作,就 会打开N个session,即每次调用getSession()和getHibernateTemplate()方法都会打开新的session。这两个 方法的区别在于:getHibernateTemplate()方法结束时会自动关闭连接,而getSession()方法必须手动关闭。
(4) 如果在方法中采用SessionFactory的openSession()方法获得连接进行操作,那么无法对其进行事务控制。
(5) 一般的开发中,通常采用getHibernateTemplate()方法进行数据库操作, getHibernateTemplate()方法采用模板+回调的机制,进行数据库操作很方便,可以查看(其中session的打开与关闭都是在 doExecute方法中进行的):

 

http://lijiejava.iteye.com/blog/667644
http://lijiejava.iteye.com/blog/727249

分享到:
评论

相关推荐

    Spring与Hibernate集成中的session

    Spring与Hibernate集成中的session.doc

    Spring_Hibernate集成

    Hibernate Session的轻量级封装 * 默认情况下运行期异常才会回滚(包括继承了RuntimeException子类),普通异常是不会滚的 * 编写业务逻辑方法时,最好将异常一直向上抛出,在表示层(struts)处理 * 关于事务...

    Spring2.5和Hibernate3集成--学习spring aop ioc

    Spring2.5和Hibernate3集成 采用声明式事务 1.声明式事务的配置 * 配置sessionFactory * 配置事务管理器 * 配置事务的传播特性 * 配置哪些类哪些方法使用事务 2.编写业务逻辑方法 * 继承...

    集成spring的hibernate懒加载

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

    Spring-Reference_zh_CN(Spring中文参考手册)

    12.2.2. 在Spring的application context中创建 SessionFactory 12.2.3. HibernateTemplate 12.2.4. 不使用回调的基于Spring的DAO实现 12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. ...

    SHH整合(mysql,struts2 2.2+spring2.5+hibernate3.0,log,jquery,标签等)DEMO

    1、SHH整合 详细清晰的标准配置,主流的应用配置,struts2.2+spring2.5+hibernate3.0 2、结合MYSQL轻量级数据库,有写好的库表sql 3、整合日志管理配置,及Spring代理日志管理的配置及应用 4、应用WEB前段主流技术,...

    从零开始学Spring Boot

    1.1 前言 1.2 资料官网 ...1.41 Spring Boot分布式Session状态保存Redis 1.42 Spring Boot Shiro权限管理 1.43 Spring Boot Shiro权限管理 1.44 Spring Boot Shiro权限管理 1.45 Spring Boot Shiro权限管理

    Spring中文帮助文档

    6.8.1. 在Spring中使用AspectJ进行domain object的依赖注入 6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ加载时织入(LTW) 6.9. 更多资源 7...

    Spring 2.0 开发参考手册

    6.8.4. 在Spring应用中使用AspectJ Load-time weaving(LTW) 6.9. 其它资源 7. Spring AOP APIs 7.1. 简介 7.2. Spring中的切入点API 7.2.1. 概念 7.2.2. 切入点实施 7.2.3. AspectJ切入点表达式 7.2.4. ...

    spring chm文档

    6.8.1. 在Spring中使用AspectJ来为domain object进行依赖注入 6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ Load-time weaving(LTW) 6.9. ...

    Spring API

    6.8.1. 在Spring中使用AspectJ进行domain object的依赖注入 6.8.2. Spring中其他的AspectJ切面 6.8.3. 使用Spring IoC来配置AspectJ的切面 6.8.4. 在Spring应用中使用AspectJ加载时织入(LTW) 6.9. 更多资源 7...

    Spring面试题

    面向切面编程(AOP)完善spring的依赖注入(DI),面向切面编程在spring中主要表现为两个方面 1.面向切面编程提供声明式事务管理 2.spring支持用户自定义的切面 面向切面编程(aop)是对面向对象编程(oop)的...

    springmybatis

    mybatis实战教程mybatis in action之五与spring3集成附源码 mybatis实战教程mybatis in action之六与Spring MVC 的集成 mybatis实战教程mybatis in action之七实现mybatis分页源码下载 mybatis实战教程mybatis in ...

    低清版 大型门户网站是这样炼成的.pdf

    6.4.1 spring 2.5集成orm中间件hibernate 3.2 404 6.4.2 spring 2.5集成mvc框架struts 2 411 6.4.3 ssh 2组合框架的基本开发步骤—eportal启程 414 6.5 小结 423 第2篇 实践篇 第7章 ssh 2热身——构建新闻发布...

    SSH的jar包.rar

    SSH(struts+spring+hibernate)的jar包 SSH 通常指的是 Struts2 做前端控制器,Spring 管理各层的组件,Hibernate 负责持久化层。 一个请求在Struts2框架中的处理大概分为以下几个步骤: 1、客户端初始化一个指向...

    Java Web程序设计教程

    第14章spring与struts2、hibernate框架的整合基础 277 14.1spring与struts2的整合方式 277 14.1.1struts2应用的扩展方式 277 14.1.2spring插件的应用 278 14.2spring和hibernate的整合 279 14.2.1spring对...

    spring-jpa-wicket-bootstrap:使用 Spring、JPA、Hibernate、Wicket 和 Bootstrap 的 J2EE Web 模板。 在 Tomcat 和 Postgres DB 上测试

    这是一个工作模板项目,它展示了一个示例多层 J2EE Web 应用程序,其中包含Apache Wicket 、 Spring IoC 、 JPA/Hibernate集成和基于Bootstrap的前端。 它演示了MvC 、 SoC 、 IoC 、 DAO 、 Service layer和Open ...

    火炬博客系统7

    可以很好的支持AOP(面向切面编程)的开发模式,Spring能有效地组织中间层对象,通过Bean容器为业务对象、DAO对象和资源对象提供了IOC类型的装配能力,将Struts和Hibernate集成起来,使用Spring构建的应用程序易于...

    火炬博客系统6

    可以很好的支持AOP(面向切面编程)的开发模式,Spring能有效地组织中间层对象,通过Bean容器为业务对象、DAO对象和资源对象提供了IOC类型的装配能力,将Struts和Hibernate集成起来,使用Spring构建的应用程序易于...

    火炬博客系统5

    可以很好的支持AOP(面向切面编程)的开发模式,Spring能有效地组织中间层对象,通过Bean容器为业务对象、DAO对象和资源对象提供了IOC类型的装配能力,将Struts和Hibernate集成起来,使用Spring构建的应用程序易于...

Global site tag (gtag.js) - Google Analytics