Hibernate懒加载问题的5种解决方案

**java

一、Hibernate基础

**
Hibernate基础,传送门web

**spring

二、什么是Hibernate懒加载

**sql

当咱们查询一个对象的时候,在默认状况下,返回的只是该对象的代理对象,当用户去使用该对象的属性时,才会向数据库再一次发出查询语句。数据库

例如,有一个对象是Employee,还有一个对象是Department。显然,对于Employee相对Department来讲,是多对一的关系;而对于Department相对Employee来讲,是一对多的关系。当咱们查询Employee对象的时候,若是但愿经过employee对象的属性department查询到所对应的Department,那么是会抛出异常的。这是由于懒加载的存在,在session关闭以后,hibernate又向数据库发出一次请求,结果就抛出异常了。session

**app

三、懒加载的4种解决方案

**框架

3.1 显式初始化(在查询方法内部)svg

要查询某员工属于哪一个部门的时候,须要对Department进行预先查询性能

使用语句

Hibernate.initialize(Department.class);

在这里插入图片描述

3.2 修改对象关系文件,将lazy改写lazy=false,即关闭懒加载

以上两种方法,确实能够解决问题,可是缺点是不管后面是否使用该对象,hibernate都会向数据库发出SQL语句请求数据,形成没必要要的性能浪费。

3.3 使用过滤器(web项目)

①获取session的方式必须使用getCurrentSession

②特殊的关闭session方式

public void doFilter(ServletRequest request, ServletResponse response, 
   FilterChain arg2) throws IOException, ServletException { 
  // TODO Auto-generated method stub 
  Session session = null; 
  Transaction tx = null; 
  try { 
   session = HibernateUtil.getCurrentSession(); 
   tx = session.beginTransaction(); 
   arg2.doFilter(request, response);//请求一直在走 
   tx.commit(); 
  } catch (Exception e) { 
   // TODO: handle exception 
   if(tx != null){ 
    tx.rollback(); 
   } 
  }finally{ 
   //特殊的关闭方式 
   HibernateUtil.closeCurrentSession(); 
  } 
 }

3.4 在SSH框架中,使用spring提供的openSessionView

其原理和第三种方法中使用Filter相似,只不过这个filter是spring提供的。使用时只须要在web.xml文件配置以下:

<!-- 使用spring解决懒加载问题 --> 
 <filter> 
  <filter-name>OpenSessionInViewFilter</filter-name> 
  <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> 
 </filter> 
 <filter-mapping> 
  <filter-name>OpenSessionInViewFilter</filter-name> 
  <url-pattern>/*</url-pattern> 
 </filter-mapping>

第3和第4中方法也能解决懒加载的问题,其中第4种方法也是目前使用较多的。可是这两种方法也是有缺点的,缺点就是延长了session关闭的时间,session的生命周期变长。没有使用该方法以前,session是在查询完数据以后,就被关闭了;而如今,session的关闭是在一次web请求的最后才关闭。

3.5 将hibernate的抓取策略改成join

,也就是left join fetch 或inner join fetch语法, 就是在<many-to-one …/>中配置lazy=“false” fetch=“join” 便可。如:

<many-to-one name="worker" lazy="false" fetch="join" class="com.paixie.dpmain.Worker">

  <column name="positionId"></column>

 </many-to-one>

**

四、hibernate中的懒加载和急加载的区别

**

懒加载: FatchType.LAZY :在加载一个实体的时候,不会立刻从数据库中加载,即从数据库中加载到内存。

急加载:FatchType.EAGER :在加载一个实体时,会当即从数据库中查询,与其关联的类也会被同时查询。

在咱们使用@ManyToOne等时,都会被默认为急加载。

在hibernate中,咱们不管是使用懒加载仍是急加载,get方法都会一次加载全部基本数据类型属性的值,而load则不一样。

在咱们开启了懒加载以后,load方法只会加载id属性,全部的非id属性的访问操做都不会执行。只有id属性中有实际值(其实就是你调用load方法时传的那个),

在session没有关闭的以前,若是访问除id外的其余属性才会发sql语句去查询,咱们常常犯的一个错误就是在当前session关闭之后访问由load()加载的对象的非id属性,

此时Hibernate尝试经过当前session发sql查询,但发现session已经关闭,这样就会发出no session的异常 。

通常咱们将将FetchType.lazy 改为 EAGER ,就能够避免这个错误。

可是在咱们须要查询一个表时,若是这个表有不少与其关联的表,若是使用急加载的话,在第一次加载就会很慢,若是是懒加载相对则会快一些。可是在咱们又须要查询与此表相关的数据的时候

急加载就会很快,由于在第一次加载的时候,已经帮咱们所有加载好了。而懒加载则会相对慢一些,由于在我门须要查询的时候,它才会帮咱们去查。

因此让他们算是各有优缺点。

而咱们用哪种方法更好,则须要根据咱们的具体状况去使用了