这篇博客将学习hibernate的缓存策略,缓存是hibernate提高性能的主要方法。
在hibernate中缓存主要分为:session的缓存,sessionFactory的缓存,其中,sessionFactory缓存又分为:内置缓存和外置缓存,关于缓存有一下几点需要说明:
1.session的缓存和sessionFactory的内置缓存,都是内置的,成为hibernate的一级缓存。
2.sessionFactory的内置缓存中包含了映射元数据的预定义sql。
3.sessionFactory的外置缓存是一个可以配置的插件。默认是不开启的,需要我们手动配置,外置缓存的数据是数据库数据的拷贝,外置缓存的存放地方可以是内存或者硬盘。
内置缓存
内置缓存是不能取消的,均由session来管理
session缓存:缓存普通的属性
sessionFactory缓存:缓存对象类型的数据
当session关闭的时候,sessionFactory中缓存的对象将被清空。
外置缓存
外置缓存也叫二级缓存,是可以配置的,二级缓存缓存的是实体对象。
一级缓存测试
1.get方法测试
UserInfo userInfo = (UserInfo) session.get(UserInfo.class,10);
System.out.println(userInfo.getUserName());
System.out.println(userInfo.getUserName());
System.out.println(userInfo.getUserName());
System.out.println(userInfo.getUserName());
System.out.println(userInfo.getUserName());
这里我们获得id=10的userinfo对象,然后连续四次得到该对象的username属性,sql语句打印如下:
可以发现只有hibernate只发出了一条sql查询语句。
2.load方法测试
如果我们将上面通过get方法得到的实体类对象,改为load方法来加载,同样的,hibernate会只发出一条查询语句。
3.list方法测试
Session session = factory.openSession();
String hql = "from UserInfo";
Listlists = session.createQuery(hql).list();
UserInfo userInfo = (UserInfo) session.load(UserInfo.class,10);
System.out.println(userInfo.getUserName());
UserInfo userInfo2 = (UserInfo) session.load(UserInfo.class,10);
System.out.println(userInfo2.getUserName());
System.out.println(userInfo.getUserName());
System.out.println(userInfo.getUserName());
System.out.println(userInfo.getUserName());
此时hibernate同样只发出一条sql语句。
可以发现,首先查询所有数据,然后将其缓存到session中,再次查询的时候,不需要在从数据库当中查询。
为什么数据会缓存到session中
为什么hibernate查询出来的数据会缓存到session当中,我们先来看个例子:
Session session = factory.openSession();
String hql = "from UserInfo";
Listlists = session.createQuery(hql).list();
session.close();
session = factory.openSession();
UserInfo userInfo = (UserInfo) session.load(UserInfo.class,10);
System.out.println(userInfo.getUserName());
UserInfo userInfo2 = (UserInfo) session.load(UserInfo.class,10);
System.out.println(userInfo2.getUserName());
System.out.println(userInfo.getUserName());
System.out.println(userInfo.getUserName());
System.out.println(userInfo.getUserName());
这里我只是在查询完成所有数据以后,增加了一条关闭session的语句。此时当再次load方法查询的时候,又会重新发出一条sql语句。这充分说明查询出的数据是缓存到session当中的。

session不能从缓存中取数据
Session session = factory.openSession();
String hql = "from UserInfo";
Listlists = session.createQuery(hql).list();
for (UserInfo userInfo : lists) {
System.out.println(userInfo.getUserName());
}
Listlists2 = session.createQuery(hql).list();
for (UserInfo userInfo : lists2) {
System.out.println(userInfo.getUserName());
}
这里我两次通过list方法查询数据。hibernate发出的sql如下:
可以看出。list只能给缓存中存放数据,但是再次查询的时候还是会发出sql查询所有的语句。
iterator查询
刚才说了,list是只能给缓存中存放数据,但是却不能从缓存当中取数据。iterator是可以的,那么iterator是怎么做到的呢??看下面的代码:
String hql = "from UserInfo";
Iteratoritertor = session.createQuery(hql).iterate();
while (itertor.hasNext()) {
System.out.println(itertor.next().getUserName());
}
Iteratoritertor2 = session.createQuery(hql).iterate();
while (itertor2.hasNext()) {
System.out.println(itertor2.next().getUserName());
}
这里两次通过iterator查询所有的数据,此时hibernate发出的sql语句如下图:

list和iterator结合使用
我们现在已经知道了,list是可以给缓存当中存放数据的,可是不可以从缓存当中取数据,list查询只发出一条sql查询所有的语句即可,而it