缓存是位于应用程序与永久性数据存储源之间用于临时存放复制数据的内存区域,缓存可以降低应用程序之间读写永久性数据存储源的次数,从而提高应用程序运行性能。
事务范围、进程范围(进程内所有事务共享,并发访问缓存,必要的隔离机制)、集群范围(缓存被一个或多个计算机进程共享,缓存数据被复制到集群中每个进程节点,进程间通过远程通信来保证缓存中数据的一致性)。
Hibernate一级缓存:
由Session提供,当程序调用Session的save()/update()/saveOrUpdate()/get()/load()或者Query和Criteria实例的list()/iterate()方法时,如果Session缓存中没有相应对象,Hibernate会把对象加入到一级缓存中,当Session关闭,该Session管理的一级缓存也会立即被清除。
在同一个Session中发出两次get查询
public void testGet_1(){
Session session=HibernateSessionFactory.getSession();
Users user1=(Users)session.get(Users.class,1);
System.out.println(user1.getLoginName());
Users user2=(Users)session.get(Users.class,1);
System.out.println(user2.getLoginName());
HIbernateSessionFactory.closeSession();
}
测试类控制台输出一条查询语句,第一次get查询数据库,第二次get在一级缓存中找到,不再插数据库。
两个Session中发出两次get
控制台输出两条查询语句,第一次关闭了session,缓存被清除了。
iterate查询测试:
public void testIterator_1(){
Session session=HibernateSessionFactory.getSession();
Users user1=(Users)session.createQuery("from Users u where u.id=1").iterate().next();
System.out.println(user1.getLoginName());
Users user2=(Users)session.createQuery("from Users u where u.id=1").iterate().next();
System.out.println(user2.getLoginName());
HibernateSessionFactory.closeSession();
}
三条查询语句,第二次执行iterate().next()会发出查询id的SQL语句,但不会发出查询实体对象的语句,因为iterate使用缓存。
Hibernate: select users0_.id as col_0_0_ from bookshop.users users0_ where users0_.id=13
Hibernate: select users0_.id as id1_7_0_, users0_.LoginName as LoginNam2_7_0_, users0_.LoginPwd as LoginPwd3_7_0_, users0_.Name as Name4_7_0_, users0_.Address as Address5_7_0_, users0_.Phone as Phone6_7_0_, users0_.Mail as Mail7_7_0_ from bookshop.users users0_
where users0_.id=?
zhangsan
Hibernate: select users0_.id as col_0_0_ from bookshop.users users0_ where users0_.id=13
zhangsan
iterate查询属性测试:
String loginName1=(String)session.createQuery("select u.loginName from Users u where u.id=1").iterate().next();
控制台输出两条查询属性的sql语句,因为iterate查询普通属性,一级缓存不会缓存,所以不会发出SQL。
Session接口为应用程序提供了两个管理缓存的方法:evict()方法和clear()方法。
evict()用于将某个对象从Session一级缓存清除;clear()方法将一级缓存所有对象清除。 session.clear().
Hibernate二级缓存:
二级缓存是一个可插拔的缓存插件,它是由SessionFactory负责管理的。
由于SessionFactory对象的生命周期与应用程序的整个过程对应,因为,二级缓存是进程范围或者集群范围的缓存。
与一级缓存一样,二级缓存也根据对象的ID来加载与缓存。当执行某个查询获得的结果集为实体对象集时,Hibernate就会把他们按照对象ID加载到二级缓存中。在访问指定ID对象时,首先从一级缓存查找,找到就直接使用,找不到则转到二级缓存查找(必须配置且启用二级缓存)。如果二级缓存找到则直接使用,否则查询数据库,并将查询结果根据对象ID放到缓存中。
Hibernate二级缓存功能是通过配置二级缓存插件来实现的。常用插件包括:EHCache、OSCache、SwarmCache、JBossCache。
Hibernate中使用EHCache的配置:
hibernate-release-xx.Final/lib/optional/ehcache目录下ehcache-core-xxx.jar、hibernate-ehcache-xx.Final.jar、slf4j-api-xx.jar三个jar包复制到webroot/web-inf/lib
创建配置文件ehcache.xml:可以直接解压hibernate-release-xx.Final/project/etc/ehcache.xml复制到项目HibTest2的src目录下。
<ehcache>
<diskStore path="java.io.tmpdir"/> //diskStore元素设置缓存数据文件的存储目录
<defaultCache //defaultCache元素设置缓存的默认的数据过期策略
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
<cache name="sampleCache1" //cache元素设置具体的命名缓存的数据过期策略。每个命名缓存代表一个缓存区域
maxElementsInMemory="10000" //设置缓存对象的最大数目
eternal="false" //指定是否永不过期
timeToIdleSeconds="300" //设置对象处于空闲状态的最大秒数
timeToLiveSeconds="600" //设置对象处于缓存状态的最大秒数
overflowToDisk="true" //设置内存溢出时是否将溢出对象写入硬盘
/>
</ehcache>
然后在Hibernate配置文件里面启用EHCache。
<!-- 启用二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!-- 设置二级缓存插件EHCache的Provider类 -->
<property name="hibernate.cache.region.factory_class">
org.hibernate.cache.ehcache.EhCacheRegionFactory
</property>
最后配置哪些实体类的对象需要二级缓存。(两种方式)
①在实体类的映射文件里配置:<cache usage="read-write"/>放到<class>与<id>之间,read-only、read-write、nonstrict-read-write,Ehcache插件不支持transaction事务型并发访问策略。
②在Hibernate配置文件中同一配置(推荐):在hibernate.cfg.xml中使用<class-cache>元素来配置哪些实体类对象需要二级缓存,如<class-cache usage="read-only" class="com.hibtest2.entity.Users">,注意<class-cache>必须放在所有<mapping>元素后面。
EHCache测试:
public void testGet(){
Session session1=HibernateSessionFactory.getSession();
Users user1=(Users)session1.get(Users.class, 14);
System.out.println(user1.getLoginName());
HibernateSessionFactory.closeSession();
Session session2=HibernateSessionFactory.getSession();
Users user2=(Users)session2.get(Users.class, 14);
System.out.println(user2.getLoginName());
HibernateSessionFactory.closeSession();
}
只有一条查询语句,第一次get之后,关闭了Session,一级缓存清除了,由于配置二级缓存开启,查询出结果放入二级缓存,第二次get首先一找不到,到二找,不行查库。
HIbernate中的查询缓存:
查询缓存主要针对普通属性结果集的缓存,而对于实体对象结果集只缓存ID。查询缓存生命周期,若当前关联表发生修改,那么查询缓存生命周期结束。
查询缓存基于二级缓存,使用前,必须首先配置二级缓存。之后在HIbernate配置文件中添加:<property name="hibernate.cache.use_query_cache">true</property>
此外,程序中必须手动启用查询缓存,如:query.setCacheable(true);
测试查询缓存:
开启查询缓存,关闭二级缓存
<property name="hibernate.cache.use_query_cache">true</property>
<property name="hibernate.cache.use_second_level_cache">false</property>