SSH学习-Hibernate懒惰加载&缓存机制

Posted youngchaolin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SSH学习-Hibernate懒惰加载&缓存机制相关的知识,希望对你有一定的参考价值。

Hibernate查询会先从一级缓存session中查询数据,如果session中没有会从sessionfactory中查找数据,如果前面两个都没有将从DB中查数据,这就是Hibernate的缓存机制,这样可以降低应用程序与物理数据源的交互频率,提高应用程序的性能。另外懒惰加载,就是尽可能晚的将数据库中的数据加载到内存中来,需要查询时查询数据,不需要查询的数据暂时就不查询。

一级缓存session管理方法

(1)evict(Object):将对象Object从session中清除掉,从持久状态进入到游离状态

(2)clear():将session中的所有对象都清除掉

(3)flush():将缓存中的数据与数据库中的数据进行同步

(4)contains(Object):判断session中是否包含某个对象Object

6)将保存的数据放到session:save()

7)将查询的数据放到sessionget(),load(),HQL查询

下面以一个案例进行分析,先使用get方法到一个对象存到session中,然后再重复一遍get动作,比较两个对象是否相同,如果相同说明第二次是从缓存中取出。

具体的hibernate.cfg.xml,表和实体类参考上一篇博客,这里直接调用测试方法进行测试,看看两次get得到的对象是否是同一个内存地址,如果是true说明就是同一对象。

package TestCase;

import java.util.List;
import java.util.Set;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

import Entity.book;
import Entity.user;

/**
 * 测试Hibernate关联查询
 * @author yangchaolin
 */
public class testHibernate {
    
      public static Session getSession() {
          //读取hibernate.cfg.xml配置文件
          Configuration cfg=new Configuration();
          cfg.configure("hibernate.cfg.xml");
          //创建sessionfactory
          SessionFactory factory=cfg.buildSessionFactory();
          //创建session
          Session session=factory.openSession();
          return session;
      }
      
      //测试session缓存机制
      @Test
      public void testSession() {
          //获取session
          Session session=getSession();
          //开启事务
          Transaction trans=session.beginTransaction();
          trans.begin(); 
          //执行持久层操作
          user u1=(user) session.get(user.class, 1);//查询id为1的user
          //提交事务
          //trans.commit();          
          //重复获取user对象的操作
          user u2=(user) session.get(user.class, 1);
          System.out.println("两个是否相同"+(u1==u2));
          /**
           * 测试发现结果为true,说明二次取得是保存在session中的数据
           */
          //关闭session
          session.close();
      }    
}

测试结果:

技术图片

从测试结果来看,第二次获取是从session一级缓存中获取的,并不是从DB中取出新存到内存中的对象,两者内存地址一致,输出结果为true。

懒惰加载

参考获取user为1的数据后,先打印user的id和name属性,后面再打印user的book属性,控制台发现先查询得到user 的id和name,当后面需要输出book时,再从数据库查询book,说明数据查询分了2次,不是一次性查询得到,这种现象就是懒惰加载。

映射文件中配置lazy属性到set标签下

      <!-- lazy设置为false,代表不懒惰加载,默认是懒惰加载 -->
      <set name="books" lazy="true"><!-- 实体类对应属性名 -->
        <key column="user_id"></key>
        <one-to-many class="Entity.book"></one-to-many>
      </set>
package TestCase;

import java.util.List;
import java.util.Set;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

import Entity.book;
import Entity.user;

/**
 * 测试Hibernate关联查询
 * @author yangchaolin
 *
 */
public class testHibernate {
    
      public static Session getSession() {
          //读取hibernate.cfg.xml配置文件
          Configuration cfg=new Configuration();
          cfg.configure("hibernate.cfg.xml");
          //创建sessionfactory
          SessionFactory factory=cfg.buildSessionFactory();
          //创建session
          Session session=factory.openSession();
          return session;
      }

      //测试获取user id为1的用户的信息
      @Test
      public void test() {
          //读取hibernate.cfg.xml配置文件
          Configuration cfg=new Configuration();
          cfg.configure("hibernate.cfg.xml");
          //创建sessionfactory
          SessionFactory factory=cfg.buildSessionFactory();
          //创建session
          Session session=factory.openSession();
          //创建一个事务并开启事务
          Transaction trans=session.getTransaction();
          trans.begin();
          //开始执行持久层操作
          user user=(user) session.get(user.class, 1);//1代表user的id属性值
          System.out.println(user.getId());
          System.out.println(user.getName());
          Set<book> books=user.getBooks();
          for(book book:books) {
              System.out.println(book);
          }
          //关闭session
          session.close();
      }      
    
}

打印结果:

技术图片

当将set标签下lazy设置为true,可以看出来先查询出来id和name,当需要打印book时,才查询books属性,它的查询分了两次,这就是懒惰加载,你不需要我不加载你需要时我再加载。

现在有个问题,如果第二次查询时,session提前关闭了会怎么样?结果是第二次将查询不到数据,为了避免因为懒惰加载和session提前关闭对查询结果的影响,struts2中有一个filter专门用于提前开启session,避免因为session提前关闭查询不到数据的情况,后面有机会再了解。

结论

Hibernate下无论是缓存机制还是懒惰加载,都是为了提高性能,因为其减少了应用程序对数据源的访问。

以上是关于SSH学习-Hibernate懒惰加载&缓存机制的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate 在从相关实体中删除时加载 LOBS(不应该是懒惰的)吗?

[原创]java WEB学习笔记93:Hibernate学习之路---Hibernate 缓存介绍,缓存级别,使用二级缓存的情况,二级缓存的架构集合缓存,二级缓存的并发策略,实现步骤,集合缓存,查询缓

Java工程师SSH教程从零打造在线网盘系统前言&目录

SSH系列-- hibernate基本原理&&入门demo

是否将Lazily提取的对象附加到Hibernate会话(由Hibernate支持的Spring Data)?

HIbernate学习笔记3 之 缓存和 对象的三种状态