一、什么是延迟加载

为了节省Hibernate加载对象的性能节销,在Hibernate中真正需要用到这个对象时,才会发出
    
    SQL语句来抓取这个对象。这一个过程称为延迟加载。

二、延迟加载的分类

A:实体对象的延迟加载
    
    B:一对多|多对多的延迟加载
    
    C:多对一|一对一的延迟加载
    
    D:属性的延迟加载

  • A:实体对象的延迟加载:使用session.get()和session.load()获取对象的区别就是是否开启延迟加载。

Hibernate只加载实体对象的ID,需要其他属性,才真正的发出SQL来加载这个对象。
    
    Load:采用延迟加载                    加载到的是一个代理对象
    
    Get:没有采用延迟加载                加载到的是一个实体对象。

  • 案例:

User user=(User)session.load(clazz, id);//直接返回的是代理对象

System.out.println(user.getId());//没有发送sql语句到数据库加载

user.getName();//创建真实的User实例,并发送sql语句到数据库中

  • 注意:1.不能判断User=null;代理对象不可能为空

      2.代理对象的限制:和代理关联的session对象,如果session关闭后访问代理则抛异常。session关闭之前访问数据库

  • B:一对多|多对多的延迟加载

fetch = FetchType.Lazy:表示开启延迟加载。读取班级时,不会发出读取学生的SQL语句。等真正使用学生数据时,才会发出一条SQL语句读取学生
    
    fetch = FetchType.EAGER:取消延迟加裁。读取班级会左关联读取学生。
    
    @OneToMany(cascade = { CascadeType.REMOVE },fetch=FetchType.EAGER)
    @JoinColumn(name = "classes_id")
    @OrderBy(value = " studentID desc")
    public List<StudentBean> getStuList() {
        return stuList;
    }

  • C : 多对一|一对一的延迟加裁

    默认是取消延迟加载的。
        
        @ManyToOne(fetch=FetchType.LAZY)
        @JoinColumn(name = "group_id")
        private GroupBean groupBean;

  • 延迟加载带来的问题: session关闭之后,再访问代理对象(延迟加载获取的是代理对象)会抛出“no session”异常。
package action;import java.util.Set;import javassist.compiler.ast.IntConst;import org.hibernate.Session;
import org.hibernate.Transaction;import bean.ClassBean;
import bean.StudentBean;
import util.HibernateSessionUtil;public class Test {public static void main(String[] args) {ClassBean cla=Test.load();   //当Test.load()执行完毕之后,session就被关闭,这时候再访问代理对象则会抛出异常。 使用session。get就不会出现这个问题
        System.out.println(cla.getClassName());}private static ClassBean load() {ClassBean cla = null;Session session = null;Transaction tran = null;try {session = HibernateSessionUtil.getSession();tran = session.beginTransaction();cla = (ClassBean) session.load(ClassBean.class, new Integer(2));  //使用延迟加载,获得的是代理对象
tran.commit();return cla;} catch (Exception e) {e.printStackTrace();tran.rollback();} finally {HibernateSessionUtil.closeSession();  //关闭session
        }return null;}
}

  • 橙色字体处代码会出现“no session”异常。
  • 解决延迟加载带来的问题:

    1. 在后台,把前台要显示的数据准备好。(适用于非WEB程序和WEB程序)

    2. 使用延迟加载,又要把Session关掉。而且是前台展现数据的时候,才发给SQL语句。(仅限于WEB程序) 原理:将Session的关闭延迟到页面加载完成之后,才关闭。

3. 在2的的基础上面,将在页面中手工关闭的Session代码,改为自动调用关闭。  过滤器来实现。

    1. 使用第一种方法解决延迟加载带来的问题(在后台,把前台要显示的数据准备好)
package action;import java.util.HashMap;
import java.util.Map;
import java.util.Set;import javassist.compiler.ast.IntConst;import org.hibernate.Session;
import org.hibernate.Transaction;import bean.ClassBean;
import bean.StudentBean;
import util.HibernateSessionUtil;public class Test {public static void main(String[] args) {Map<String, Object> dataMap = Test.load(); // Test.load()方法不再直接返回一个ClassBean对象然后再由这个对象得到StudentBean对象,而是// Test.load()方法里直接把ClassBean和StudentBean对象直接返回
ClassBean classBean = (ClassBean) dataMap.get("classBean");Set<StudentBean> stuSet=(Set<StudentBean>)dataMap.get("stuSet");System.out.println(stuSet.size());}private static Map<String, Object> load() {Map<String, Object> dataMap = new HashMap<String, Object>();Session session = null;Transaction tran = null;try {session = HibernateSessionUtil.getSession();tran = session.beginTransaction();ClassBean classBean = (ClassBean) session.get(ClassBean.class,new Integer(1));Set<StudentBean> stuSet = classBean.getStuSet();dataMap.put("classBean", classBean);stuSet.size();   //这行不能省略,因为classBean.getStuSet();并不会发出sql语句。dataMap.put("stuSet", stuSet);tran.commit();} catch (Exception e) {e.printStackTrace();tran.rollback();} finally {HibernateSessionUtil.closeSession(); // 关闭session
        }return dataMap;}
}

  2.使用第二种方法解决延迟加载带来的问题(是前台展现数据的时候,才发给SQL语句。(仅限于WEB程序))

  • index.jsp
 <body><a href="<%=path%>/servlet/session_1">1:解决延迟加载,将Session的关闭延迟到jsp页面中</a></body>

  • SessionServlet .java
package servlet;
import java.io.IOException;
import java.io.PrintWriter;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.hibernate.Session;import bean.ClassBean;
import util.HibernateSessionUtil;public class SessionServlet extends HttpServlet {public SessionServlet() {super();}public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {this.doPost(request, response);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {request.setCharacterEncoding("UTF-8");response.setContentType("html;charset=UTF-8");Session session = null;ClassBean classBean = null;try {session = HibernateSessionUtil.getSession();classBean = (ClassBean) session.load(ClassBean.class,new Integer(1));} catch (Exception e) {e.printStackTrace();} finally {//这里不能关闭session,在view1,jsp页面关闭seession
        }request.setAttribute("classBean", classBean);request.getRequestDispatcher("/view1.jsp").forward(request, response);}}

  • view1.jsp
 <body><pre><h2>班级信息:</h2>班级id:${requestScope.classBean.classId}班级名称:${requestScope.classBean.className}<h2>学生信息信息:</h2><c:forEach var="student" items="${requestScope.classBean.stuSet}">学生id:${student.stuId}学生名:${student.stuName}班级id:${student.classId}</c:forEach></pre><% HibernateSessionUtil.closeSession();   //在这里关闭session,确保页面取到所需要的数据后再关闭session。%></body>

结果:



  3. 案例三(在2的的基础上面,将在页面中手工关闭的Session代码,改为自动调用关闭。  过滤器来实现。)

  • index.jsp
 <body><a href="<%=path%>/servlet/session_1">1:在过滤器中统一关闭session</a></body>

  • SessionServlet.java
public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {request.setCharacterEncoding("UTF-8");response.setContentType("html;charset=UTF-8");Session session = null;ClassBean classBean = null;try {session = HibernateSessionUtil.getSession();classBean = (ClassBean) session.load(ClassBean.class,new Integer(1));} catch (Exception e) {e.printStackTrace();} finally {//这里不能关闭session,在view1,在过滤器中关闭seession
        }request.setAttribute("classBean", classBean);request.getRequestDispatcher("/view1.jsp").forward(request, response);}

  • HibernateFilter.java
package filter;import java.io.IOException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;public class HibernateFilter implements Filter {private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();private static org.hibernate.SessionFactory sessionFactory;private static Configuration configuration = new Configuration();private static ServiceRegistry serviceRegistry;@Overridepublic void init(FilterConfig arg0) throws ServletException {try {configuration.configure();serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();sessionFactory = configuration.buildSessionFactory(serviceRegistry);} catch (Exception e) {System.err.println("%%%% Error Creating SessionFactory %%%%");e.printStackTrace();}}@Overridepublic void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException {try {System.out.println("hello");chain.doFilter(req, res);} catch (Exception e) {e.printStackTrace();} finally {HibernateFilter.closeSession(); // 在过滤器中统一关闭session
        }}@Overridepublic void destroy() {}public static Session getSession() throws HibernateException {Session session = (Session) threadLocal.get();if (session == null || !session.isOpen()) {if (sessionFactory == null) {rebuildSessionFactory();}session = (sessionFactory != null) ? sessionFactory.openSession(): null;threadLocal.set(session);}return session;}public static void rebuildSessionFactory() {try {configuration.configure();serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();sessionFactory = configuration.buildSessionFactory(serviceRegistry);} catch (Exception e) {System.err.println("%%%% Error Creating SessionFactory %%%%");e.printStackTrace();}}public static void closeSession() throws HibernateException {Session session = (Session) threadLocal.get();threadLocal.set(null);if (session != null) {session.close();}}}

  • view1.jsp
  <body><pre><h2>班级信息:</h2>班级id:${requestScope.classBean.classId}班级名称:${requestScope.classBean.className}<h2>学生信息信息:</h2><c:forEach var="student" items="${requestScope.classBean.stuSet}">学生id:${student.stuId}学生名:${student.stuName}班级id:${student.classId}</c:forEach></pre></body>

结果与上例差不多。


总结:一般使用第二种解决方式来解决延迟加载带来的问题。


D.  属性的延迟加载

  • 大字段的属性上面(Oracle中的Clob和Blog,SQLServer中的TExt和Image2种字段),String,int属性没有必要延迟加载。

1:设定延迟加载的注解  
            // Text映射为string类型
            @Lob
            @Basic(fetch = FetchType.LAZY)
            
            private String content;
            // image映射为字节数组。
            @Lob
            @Basic(fetch = FetchType.LAZY)
            
            private byte[] filedata;

2:要对对象实现类增强机制。
      使用Ant来完成。

  • build.xml
 <?xml version="1.0" encoding="UTF-8"?><project name="Hibernate_Project_7" default="instrument" basedir="."><property name="lib.dir" value="./WebRoot/WEB-INF/lib" /><property name="classes.dir" value="./WebRoot/WEB-INF/classes" /><path id="lib.class.path"><fileset dir="${lib.dir}"><include name="**/*.jar" /></fileset></path><target name="one"></target><target name="two"></target><target name="instrument"><taskdef name="instrument"classname="org.hibernate.tool.instrument.javassist.InstrumentTask"><classpath path="${classes.dir}" /><classpath refid="lib.class.path" /></taskdef><instrument verbose="true"><fileset dir="${classes.dir}/com/bean"><include name="LobBean.class" />   <!-- 每次修改LobBean的代码后都需要重新运行ant,否则这个ant会失效 --></fileset></instrument></target></project>      

  • 案例
  • BlobBEAN.java
package bean;import java.io.Serializable;import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;@Entity
@Table(name = "t_blob")
public class BlobBEAN implements Serializable {@Id@Column(name = "blodid")private Integer blobId;private String name;// String类型映射为文本大字段
    @Basic(fetch=FetchType.LAZY)@Lobprivate String content;// 视频/图片等大字段映射为字节数组
    @Basic(fetch=FetchType.LAZY)@Lobprivate byte[] image;public String getName() {return name;}public void setName(String name) {this.name = name;}public BlobBEAN(Integer blobId, String name, String content, byte[] image) {super();this.blobId = blobId;this.name = name;this.content = content;this.image = image;}public BlobBEAN() {super();// TODO Auto-generated constructor stub
    }public Integer getBlobId() {return blobId;}public void setBlobId(Integer blobId) {this.blobId = blobId;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public byte[] getImage() {return image;}public void setImage(byte[] image) {this.image = image;}}

  • build.xml
<?xml version="1.0" encoding="UTF-8"?><project name="hibernate_lazy" default="instrument" basedir="."> <!--default指默认执行的arget   --><property name="lib.dir" value="./WebRoot/WEB-INF/lib" /> <!--设置lib文件夹的路径  --><property name="classes.dir" value="./WebRoot/WEB-INF/classes" /> <!--设置classes文件夹的路径  --><path id="lib.class.path"><fileset dir="${lib.dir}"><include name="**/*.jar" /> <!-- 引用${lib.dir}路径中所有的jar包--></fileset></path><target name="instrument"><taskdef name="instrument"classname="org.hibernate.tool.instrument.javassist.InstrumentTask"><classpath path="${classes.dir}" /><classpath refid="lib.class.path" /></taskdef><instrument verbose="true"><fileset dir="${classes.dir}/bean">  <include name="BlobBEAN.class" />  <!-- 每次修改BlobBEAN的代码后都需要重新运行ant,否则这个ant会失效 --></fileset></instrument></target>
</project>

  • Test.java
package action;import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;import org.apache.commons.io.IOUtils;
import org.hibernate.Session;
import org.hibernate.Transaction;import bean.BlobBEAN;
import util.HibernateSessionUtil;public class Test {public static void main(String[] args) {
//        Test.save();
        Test.load();}private static void save() {Session session = null;Transaction tran = null;try {session = HibernateSessionUtil.getSession();tran = session.beginTransaction();BlobBEAN blobBean = new BlobBEAN();blobBean.setBlobId(1);// Text类型StringBuffer str = new StringBuffer();for (int i = 0; i < 10000; i++) {str.append("abcabc");}blobBean.setContent(str.toString());// Image类型String path = "F:\\123.jpg";InputStream inputStream = new FileInputStream(new File(path));byte[] imaBytes = IOUtils.toByteArray(inputStream);blobBean.setImage(imaBytes);session.save(blobBean);tran.commit();} catch (Exception e) {e.printStackTrace();tran.rollback();} finally {HibernateSessionUtil.closeSession();}}private static void load() {Session session = null;Transaction tran = null;try {session = HibernateSessionUtil.getSession();tran = session.beginTransaction();BlobBEAN blob=(BlobBEAN)session.get(BlobBEAN.class, new Integer(1));System.out.println(blob.getName());//属性的延迟加载,加载任意一个大字段时,会加载所有的属性延迟字段。String content=blob.getContent();OutputStream out=new FileOutputStream(new File("F:\\123.txt"));IOUtils.write(content, out);out.flush();out.close();tran.commit();} catch (Exception e) {e.printStackTrace();tran.rollback();} finally {HibernateSessionUtil.closeSession();}}}

转载于:https://www.cnblogs.com/shyroke/p/6905609.html

(十六)Hibernate中的延迟加载相关推荐

  1. [unreal4入门系列之十六] UE4中的集合:TSet容器

    一.TSet<T>是什么 UE4中,除了TArray动态数组外,还提供了各种各样的模板容器.这一节,我们就介绍集合容器--TSet<T>.类似于TArray<T>, ...

  2. WPF入门教程系列十六——WPF中的数据绑定(二)

    三.绑定模式 通过上一文章中的示例,学习了简单的绑定方式.在这里的示例,要学习一下绑定的模式,和模式的使用效果. 首先,我们来做一个简单示例,这个示例是根据ListBox中的选中项,去改变TextBl ...

  3. Java 基础系列(十六) --- Java中模板引擎的使用

    模板引擎 1 关于动态页面的渲染 2 非模板引擎的弊端 3 模板引擎 3.1 什么是模板引擎? 3.2 Thymeleaf 语法 3.3 模板引擎的使用 4 总结 1 关于动态页面的渲染   渲染就是 ...

  4. 避暑山庄消失的三十六景,曾经那么美!

    来源: 老家热河 过去 老家热河曾先后推出了几篇 承德人李树介绍避暑山庄的文章 图文并茂,知识性强 受到很多读者朋友的欢迎 今天 李树又为我们带来了 避暑山庄遗存三十六景 一起看看都是哪里吧 避暑山庄 ...

  5. 第十六届智能车竞赛国赛队伍中节能信标组无线电能接收方案

    §01 无线充电 在 第十六届智能车竞速赛 中,有一组"节能信标组".该组别的队伍车模允许自行设计,并且需要设计无线充电电路,从 比赛信标系统中 获取车模运行所需要的电能. 由于节 ...

  6. 解决hibernate中的懒加载(延迟加载)问题

    解决hibernate中的懒加载(延迟加载)问题 我们在开发的时候经常会遇到延迟加载问题,在实体映射时,多对一和多对多中,多的一样的属性默认是lazy="true"(即,默认是延迟 ...

  7. C语言编程>第二十六周 ⑥ 请补充fun函数,该函数的功能是:按 “0”到 “9”统计一个字符串中的奇数数字字符各自出现的次数,结果保存在数组num中。注意:不能使用字符串库函数。

    例题:请补充fun函数,该函数的功能是:按 "0"到 "9"统计一个字符串中的奇数数字字符各自出现的次数,结果保存在数组num中.注意:不能使用字符串库函数. ...

  8. 计算机中十六乘十六进制怎么算,16进制的乘法怎么算

    满意答案 momoko625 2013.04.23 采纳率:59%    等级:12 已帮助:14443人 原码乘法计算时只计算原码绝对值部分,结果的符号是根据符号位通过异或来求得. http://2 ...

  9. C语言编程>第十六周 ⑧ S是一个由数字和字母字符串组成的字符串,由变量len传入字符串长度。请补充fun函数,该函数的功能是把字符串s中的数字字符转换成数字并存放到整型数组a中

    例题:S是一个由数字和字母字符串组成的字符串,由变量len传入字符串长度.请补充fun函数,该函数的功能是把字符串s中的数字字符转换成数字并存放到整型数组a中,函数返回数组a的长度. 例如,s=&qu ...

最新文章

  1. 二叉树(中序遍历)非递归
  2. 以整体思维看问题:解决单页应用,系统角色请求覆盖身份唯一标识(本项目中是session_id命名的)发送请求问题...
  3. android自定义通知栏图标大小,Android不使用自定义布局情况下实现自定义通知栏图标的方法...
  4. Projective Dynamics: Fusing Constraint Projections for Fast Simulation
  5. 第四季-专题15-网卡驱动程序设计
  6. 5-17 汉诺塔的非递归实现 (25分)
  7. python的统计库_python--学习笔记13 统计库
  8. AJax视频教程适高级篇+源码(2G)25讲
  9. win10无法正常弹出移动硬盘/U盘
  10. vue+vant移动端入门实现5(仿网易严选)
  11. Jmeter取样器设置
  12. HDLC——高级数据链路控制(HDLC,High-level Data Link Control)
  13. MySQLSyntaxException:FUNCTION xxxxxxxx.JSON_EXTRACT does not exist
  14. Spring容器是怎么初始化的?
  15. cad绘制正八边形_软件CAD | 各种“线”工具
  16. 凹入表示法(C语言版)
  17. 同期收治患者住院天数_速看!二级公立中医医院绩效考核指标发布(附34个指标)...
  18. Eigen 矩阵的特征值特征向量求解(EVD分解)
  19. XSKY 文件存储首次进入 IDC 榜单
  20. 计算机组成原理试题及答案(含AB卷以及答案)

热门文章

  1. 句法分析-基于CKY的PCFG(概率上下文无法语法)
  2. Pr 仿漫威片头效果~
  3. LaTeX写一份完整的物理实验报告
  4. 境外IP判断一种实现方案
  5. 面试时,如何回答你还有什么想要了解的?
  6. CentOS7和CentOS8 FreeSWITCH 1.10.7 简单图形化界面20--FreeSWITCH通过域名注册
  7. qq登录无法连接服务器未响应,win7登录qq提示腾讯qq未响应的解决方法
  8. 时间--cd //lastyear
  9. 帕德逼近matlab算法,帕德逼近matlab
  10. 局域网游戏联机大厅建主模式实现附(Unity)