Hibernate框架中的缓存技术
(其中分为Session的缓存、SessionFactory的缓存,也称为一级缓存和二级疑)。
一级缓存:
一级缓存是Session级的缓存,其生命周期很短,与Session相互对应,由Hibernate进行管理,属于事务范围的缓存。当程序调用 Session的load()方法、get()方法、save()方法、saveOrUpdate()方法、update()方法或查询接口方法时,Hibernate会对实体对象进行缓存;当通过load()方法或get()方法查询实体对象时,Hibernate会首先到缓存中查询,在找不到实体对像的情况下,Hibernate才会发出SQL语句到数据库中查询,从而提高了Hibernate的使用效率。
举个例子来说吧:
package com.xqh.util;
import org.hibernate.Session;
import com.xqh.model.User;
public class Test {
public static void main(String[] args) {
Session session = null;
try {
session = HibernateUtil.getSession(); // 获取session
session.beginTransaction(); //开启事务
System.out.println("第一次查询:");
User user = (User)session.get(User.class, new Integer(1));
System.out.println("用户名:" + user.getName());
System.out.println("第二次查询:");
User user1 = (User)session.get(User.class, 1);
System.out.println("用户名:" + user1.getName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
// 出错将回滚事务
session.getTransaction().rollback();
} finally {
// 关闭Session对象
HibernateUtil.closeSession(session);
}
}
}
当程序通过get()方法第一次查用户对象时,Hibernate会发出一条SQL语句进行查询,此时Hibernate对其用户对象进行了一级缓存;当再次通过get()方法查询时,Hibernate就不会发出SQL语句了,因为用户名已经存在于一级缓存中。程序运行结果:
第一次查询:
Hibernate:
select
user0_.id as id0_0_,
user0_.name as name0_0_,
user0_.sex as sex0_0_
from
tb_user_info user0_
where
user0_.id=?
用户名:xqh
第二次查询:
用户名:xqh
注意:一级缓存的生命周期与Session相对应,它并不会在Session之间共享,在不同的Session中不能得到其他Session中缓存的实体对象
二级缓存:
二级缓存是SessionFactory级的缓存,其生命周期与SessionFactory一致。二级缓存可在多个Session间共享,属于进程范围或群集范围的缓存。
二级缓存是一个可插拔的缓存插件,它的使用需要第三方缓存产品的支持。在Hibernate框架中,通过Hibernate配置文件配置二级缓存的使用策略。
1.加入缓存配置文件ehcache.xml
<ehcache>
<!-- Sets the path to the directory where cache .data files are created.
If the path is a Java System Property it is replaced by
its value in the running VM.
The following properties are translated:
user.home - User's home directory
user.dir - User's current working directory
java.io.tmpdir - Default temp file path -->
<diskStore path="java.io.tmpdir"/>
<!--Default Cache configuration. These will applied to caches programmatically created through
the CacheManager.
The following attributes are required for defaultCache:
maxInMemory - Sets the maximum number of objects that will be created in memory
eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the element
is never expired.
timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
if the element is not eternal. Idle time is now - last accessed time
timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
if the element is not eternal. TTL is now - creation time
overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache
has reached the maxInMemory limit.
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
<!--Predefined caches. Add your cache configuration settings here.
If you do not have a configuration for your cache a WARNING will be issued when the
CacheManager starts
The following attributes are required for defaultCache:
name - Sets the name of the cache. This is used to identify the cache. It must be unique.
maxInMemory - Sets the maximum number of objects that will be created in memory
eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the element
is never expired.
timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
if the element is not eternal. Idle time is now - last accessed time
timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
if the element is not eternal. TTL is now - creation time
overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache
has reached the maxInMemory limit.
-->
<!-- Sample cache named sampleCache1
This cache contains a maximum in memory of 10000 elements, and will expire
an element if it is idle for more than 5 minutes and lives for more than
10 minutes.
If there are more than 10000 elements it will overflow to the
disk cache, which in this configuration will go to wherever java.io.tmp is
defined on your system. On a standard Linux system this will be /tmp"
-->
<cache name="sampleCache1"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
<!-- Sample cache named sampleCache2
This cache contains 1000 elements. Elements will always be held in memory.
They are not expired. -->
<cache name="sampleCache2"
maxElementsInMemory="1000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
/> -->
<!-- Place configuration for your caches following -->
</ehcache>
2.设置Hibernate配置文件。
<!-- 开启二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!-- 指定缓存产品提供商 -->
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<!-- 指定二级缓存应用到的实体对象 -->
<class-cache class="com.xqh.model.User" usage="read-only"></class-cache>
例:
package com.xqh.util;
import org.hibernate.Session;
import com.xqh.model.User;
public class Test {
public static void main(String[] args) {
Session session = null; // 第一个Session
try {
session = HibernateUtil.getSession();
session.beginTransaction();
System.out.println("第一次查询:");
User user = (User)session.get(User.class, 1);
System.out.println("用户名:" + user.getName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
// 出错将回滚事务
session.getTransaction().rollback();
} finally {
// 关闭Session对象
HibernateUtil.closeSession(session);
}
try {
session = HibernateUtil.getSession(); // 开启第二个缓存
session.beginTransaction();
System.out.println("第二次查询:");
User user = (User)session.get(User.class, 1);
System.out.println("用户名:" + user.getName());
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
// 出错将回滚事务
session.getTransaction().rollback();
} finally {
// 关闭Session对象
HibernateUtil.closeSession(session);
}
}
}
二级缓存在Session之间是共享的,因此可在不同Session中加载同一个对象,Hibernate将只发出一条SQL语句,当第二次加载对象时,Hibernate将从缓存中获取此对象。
程序结果:
第一次查询:
Hibernate:
select
user0_.id as id0_0_,
user0_.name as name0_0_,
user0_.sex as sex0_0_
from
tb_user_info user0_
where
user0_.id=?
用户名:xqh
第二次查询:
用户名:xqh
对于二级缓存,可以使用一些不经常更新的数据或参考的数据,此时其性能会得到明显的提升。但如果经常变化的数据应用二级缓存,则性能方面会造成一定问题。