Hibernate旅程(七)Hibernate缓存机制--一级缓存


Hibernate一级缓存


缓存就是你去小卖铺买东西,不用再去生产车间里买东西,当小卖铺倒闭了,也就是session缓存生命周期结束。hibernate一级缓存的声明周期很短,和session的生命周期一致,hibernate的一级缓存也叫做session级缓存,或叫事务级缓存。下面来看session控制的一级缓存。


同一session中使用两次load()进行查询。


代码入下所示,我们在同一个session中两次调用load()。

/**
    * 在同一个session中发出两次load查询
    */
   public voidtestCache1() {
      Sessionsession = null;
      try {
         //使用load查询两遍.
         session= HibernateUtils.getSession();
         session.beginTransaction();
         Studentstudent =(Student)session.load(Student.class, 1);
         System.out.println("student.name=" + student.getName());
        
         //不会发出查询语句,load使用缓存,在同一个session中.
         student =(Student)session.load(Student.class, 1);
         System.out.println("student.name=" + student.getName());
        
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
   }    

两次都采用load()进行加载并打印出学生的名字。发出的sql语句如下所示。对于loadlazy加载,只有在使用load加载上来的类,才真正的去数据库查询。控制台打印的sql代码如下所示。


从显示结果中我们可以看出,在第一次真正使用load的时候,发出sql语句。Hibernate会把查询上来真实的对象放到sessionmap中。当第二次load再次使用的时候,不会再发送sql语句,而是直接从session的缓存中取出。


同一session中使用两次get()进行查询。

源代码也就是把上述load换成get

Getload的区别,get不支持延迟加载而load支持延迟加载,但当我们在同一次访问中访问两次get方法时,可以看到当加载get方法的时候控制台立刻打印sql,同时放到了缓存中。当我们第一次调用get方法的时候,同样和load方法一样,没有再次去数据库中查询,而是直接从缓存中取出来显示。打印结果如下图所示。




在同一session中发出两次iterate查询,查询实体对象。


代码如下所示。

/**
    * 在同一个session中发出两次iterate查询,查询实体对象
    * 发出两次迭代查询.查询实体对象.
    */
   public void testCache3() {
      Sessionsession = null;
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         Iteratoriter = session.createQuery("from Student s where s.id<5").iterate();
         while(iter.hasNext()) {
            Studentstudent = (Student)iter.next();
            System.out.println(student.getName());
         }
         System.out.println("--------------------------------------");
         //它会发出查询id的语句,但不会发出根据id查询学生的语句,因为iterate使用缓存
         iter= session.createQuery("from Student s where s.id<5").iterate();
         while(iter.hasNext()) {
            Studentstudent = (Student)iter.next();
            System.out.println(student.getName());
         }
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
   } 


 

运行结果如下所示。

Hibernate旅程(七)Hibernate缓存机制--一级缓存_第1张图片

第一次调用迭代器的查询时,首先发出查询id的语句,并根据id查询学生。当第二次调用时,只会发出查询id的语句,不会再根据id来查询对应的学生对象。这说明iterate(迭代器)是支持缓存的。


在同一session中发出两次iterate查询,查询实体对象。


代码如下所示。

Session session = null;
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         Iteratoriter = session.createQuery("select s.name from Student s wheres.id<5").iterate();
         while(iter.hasNext()) {
            Stringname = (String)iter.next();
            System.out.println(name);
         }
         System.out.println("--------------------------------------");
        
         //iterate查询普通属性,一级缓存不会缓存,所以发出查询语句
         //一级缓存是缓存实体对象的
         iter= session.createQuery("select s.name from Student s wheres.id<5").iterate();
         while(iter.hasNext()) {
            Stringname = (String)iter.next();
            System.out.println(name);
         }
         session.getTransaction().commit();


 

显示结果如下所示。

Hibernate旅程(七)Hibernate缓存机制--一级缓存_第2张图片

根据显示结果可知,迭代器查询普通属性,一级缓存不会存储,所以当第二次查询的时候仍然发出查询语句。这说明iterate一级缓存缓存的是实体对象,对于普通属性不会缓存

在两个session中发出load查询。

代码如下所示。

Session session = null;
      try {
         session = HibernateUtils.getSession();
         session.beginTransaction();
         Studentstudent = (Student)session.load(Student.class, 1);
         System.out.println("student.name=" +student.getName());
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
     
      try {
         session = HibernateUtils.getSession();
         session.beginTransaction();
         Studentstudent = (Student)session.load(Student.class, 1);
         //会发出查询语句,session间不能共享一级缓存数据
         //因为他会伴随着session的消亡而消亡
         System.out.println("student.name=" +student.getName());
         session.getTransaction().commit();
 


显示结果如下所示。



从上图可以看出,会发出两次sql,这也说明了session之间不能共享一级缓存数据,因为缓存会本随着自己的那个session的消亡而消亡


在一个session中先调用save(),再调用getload查询刚刚save的数据。


代码如下所示。

/**
    * 在同一个session中先调用save,再调用load查询刚刚save的数据
    */
   public voidtestCache6() {
      Sessionsession = null;
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         Studentstudent = new Student();
         student.setName("张三");
         Serializableid = session.save(student);
         student= (Student)session.load(Student.class,id);
         //不会发出查询语句,因为save支持缓存
         System.out.println("student.name=" +student.getName());
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
   } 
 


显示结果如下所示。



从图中可以看出,只发送一次插入语句,当我们再次查询的时候,没有去数据库进行查询,这说明当使用session.save()时,已经放入缓存中。再进行查询时会从缓存中取出。


大批量数据的添加。


代码如下所示。

public voidtestCache7() {
      Sessionsession = null;
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         for (int i=0;i<100; i++) {
            Studentstudent = newStudent();
            student.setName("张三" +i);
            session.save(student);
            //每20条更新一次
            if (i %20 == 0) {
                session.flush();
                //清除缓存的内容
                session.clear();
            }
         }
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
   }       


打印sql如下图所示。

Hibernate旅程(七)Hibernate缓存机制--一级缓存_第3张图片

 

从图中可知,打印了100inset语句,在一个session中缓存100条数据很大,我们可以设置每20条清空缓存。

 

Hibernate一级缓存总结


从上可知,loadgetiterate查询实体对象时,支持一级缓存,但查询普通属性时不支持一级缓存,当我们大批量数据插入或更新时,由于缓存中数据量太大,我们可以设置缓存中的条数,使用session.clear()来清除缓存。

 

 

你可能感兴趣的:(Hibernate一级缓存)