hibernate缓存的学习

这篇博客将学习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";
List<UserInfo>lists = 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";
List<UserInfo>lists = 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";
List<UserInfo>lists = session.createQuery(hql).list();
for (UserInfo userInfo : lists) {
    System.out.println(userInfo.getUserName());
}
List<UserInfo>lists2 = 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";
Iterator<UserInfo>itertor = session.createQuery(hql).iterate();
while (itertor.hasNext()) {
            System.out.println(itertor.next().getUserName());
}

Iterator<UserInfo>itertor2 = session.createQuery(hql).iterate();
while (itertor2.hasNext()) {
            System.out.println(itertor2.next().getUserName());
}

这里两次通过iterator查询所有的数据,此时hibernate发出的sql语句如下图:
这里写图片描述

list和iterator结合使用

我们现在已经知道了,list是可以给缓存当中存放数据的,可是不可以从缓存当中取数据,list查询只发出一条sql查询所有的语句即可,而iterator是可以从缓存当中读取数据的,如果使用iterator查询所有数据,会首先查询所有的id,然后根据id一次发出sql语句,查询每一条记录,这样无形当中就降低了查询效率,那么我们可以根据这些特性,将list查询和iterator查询结合起来使用。
我们可以首先使用list查询所有,这样只会发出一条查询语句,不必想iterator那样发出n+1条sql语句,提升了查询效率,第一次之后查询所有数据的时候,就可以直接使用iterator来查询,这样可以只查询所有的id,然后根据id从缓存当中取数据,代码如下:

String hql = "from UserInfo";
List<UserInfo>lists = session.createQuery(hql).list();
for (UserInfo userInfo : lists) {
    System.out.println(userInfo.getUserName());
}
Iterator<UserInfo>itertor = session.createQuery(hql).iterate();
while (itertor.hasNext()) {
            System.out.println(itertor.next().getUserName());
}

此时hibernate发出的sql和我们预期的一样:
这里写图片描述

hibernate二级缓存

在hibernate中,二级缓存默认是打开的,一般来讲,hibernate的二级缓存是和应用的生命周期是一样的,由于二级缓存的数据每一个session都可以进行访问和更改,所以如果出现高并发的时候,有可能会出现问题。
1.添加ecache所需的jar文件:
在hibernate-release-4.3.10.Final\lib\optional\ehcache目录下有这样三个jar文件,需要加入到工程中:
slf4j-api-1.6.1.jar
hibernate-ehcache-4.3.10.Final.jar
ehcache-core-2.4.3.jar
2.配置二级缓存:
在hibernate.cfg.xml文件中进行配置:

<!-- 配置缓存提供类 -->
<property name="cache.provider_class">
    org.hibernate.cache.EhCacheProvider
</property>
<!-- 启用查询缓存 -->
<property name="cache.use_query_cache">true</property>

所谓查询缓存就是让hibernate缓存list,iterator,createQuery等方法的查询结果集,如果没有打开查询缓存,hibernate将只缓存load方法获得的单个持久化对象。
注意:在打开查询缓存 之后,调用query.list()之前,必须显示调用query.setCacheable(true)来标识该查询使用缓存。
3.建立ehcache.xml,在类路径下:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>  
    <diskStore path="java.io.tmpdir"/>  
    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        maxElementsOnDisk="10000000"
        diskPersistent="false"
        diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU"
        />
</ehcache>

说明一下:
diskStore表示设置cache文件的存放目录,有如下三种配置:
1.user.home 表示用户的主目录
2.user.home 表示用户当前的工作目录
3.java.io.tmpdir 默认的temp文件目录
maxElementsInMemory :在内存中最大的对象缓存数量
eternal :设置是否为永久缓存,如果是永久缓存,则timeout将被忽略。
可选的属性:
timeToIdleSeconds:表示设置元素过期前的空闲时间
timeToLiveSeconds:表示设置元素过期前的活动时间
diskPersistent:表示是否disk store在虚拟机启动时持久化。默认为false
diskExpiryThreadIntervalSeconds:表示运行disk终结线程的时间,默认为120秒
memoryStoreEvictionPolicy:表示策略关于Eviction
4.配置映射文件
在需要被缓存的类对应的映射文件中配置hibernate的缓存策略

<cache usage="read-write"/><!--  配置hibernate缓存策略 -->

这里我配置的缓存策略是可读写的。该配置有如下一些值:
1.read-only :表示无需修改的数据。
2.read-write :需要更新数据
3.nonstrict-read-write 非严格读写缓存策略。只需要偶尔更新数据,并且也不需要十分严格的事物隔离。
5.编写测试代码:

Query query = session.createQuery("from UserInfo");
query.setCacheable(true)
List<UserInfo> list = query.list();
for (UserInfo userinfo : list) {
    System.out.println(userinfo.getUid()+"---"+userinfo.getUname());
}
session.close();
Session session2 = sf.openSession();
UserInfo userinfo =(UserInfo)session2.get(UserInfo.class, 1);       System.out.println(userinfo.getUid()+"***"+userinfo.getUname());

这里,虽然第一次查询完成后session就已经关闭,但是由于配置了二级缓存,所以当session2再次查询的时候,是不需要再发出sql语句从数据库当中查询的。

关于hibernate的缓存的学习就到这里了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值