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

最后更新于:2022-04-01 14:49:59

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代码如下所示。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-21_576908f9b4564.jpg) 从显示结果中我们可以看出,在第一次真正使用load的时候,发出sql语句。Hibernate会把查询上来真实的对象放到session的map中。当第二次load再次使用的时候,不会再发送sql语句,而是直接从session的缓存中取出。 ### 同一session中使用两次get()进行查询。 源代码也就是把上述load换成get。 Get和load的区别,get不支持延迟加载而load支持延迟加载,但当我们在同一次访问中访问两次get方法时,可以看到当加载get方法的时候控制台立刻打印sql,同时放到了缓存中。当我们第一次调用get方法的时候,同样和load方法一样,没有再次去数据库中查询,而是直接从缓存中取出来显示。打印结果如下图所示。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-21_576908f9c95a6.jpg) ### 在同一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); } } ~~~ 运行结果如下所示。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-21_576908f9e5afd.jpg) 第一次调用迭代器的查询时,首先发出查询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(); ~~~ 显示结果如下所示。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-21_576908fa10478.jpg) 根据显示结果可知,迭代器查询普通属性,一级缓存不会存储,所以当第二次查询的时候仍然发出查询语句。这说明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(); ~~~ 显示结果如下所示。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-21_576908fa2e6e2.jpg) 从上图可以看出,会发出两次sql,这也说明了session之间不能共享一级缓存数据,因为缓存会本随着自己的那个session的消亡而消亡。 ### 在一个session中先调用save(),再调用get或load查询刚刚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); } } ~~~ 显示结果如下所示。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-21_576908fa46506.jpg) 从图中可以看出,只发送一次插入语句,当我们再次查询的时候,没有去数据库进行查询,这说明当使用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如下图所示。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-21_576908fa5c8c0.jpg) 从图中可知,打印了100条inset语句,在一个session中缓存100条数据很大,我们可以设置每20条清空缓存。 ### Hibernate一级缓存总结 从上可知,load、get、iterate查询实体对象时,支持一级缓存,但查询普通属性时不支持一级缓存,当我们大批量数据插入或更新时,由于缓存中数据量太大,我们可以设置缓存中的条数,使用session.clear()来清除缓存。
';