Hibernate是一个持久层框架,经常访问物理数据库,为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据
Hibernate缓存主要分为三类
一级缓存又称session缓存,生命周期和session相同,周期较短。事务级别的缓存(我们提交一个事务后就把session关闭掉了)一级缓存是内置的,无法卸载的
get使用了一级缓存,用get获取数据的时候,首先检查缓存中是否有这个数据,如果有直接从缓存中取数据,如果没有查询数据库,同时将数据保存到缓存中
load也使用了一级缓存,同时还支持lazy,当load从数据库查询到数据时也会把数据放入缓存中
unique/list查询不会去查看缓存,但是list查询的实体对象将会放入缓存中。
iterate会执行查询id的操作(当需要对象的时候才会根据id去查找对象),当查询对象时,会检查缓存中是否存在。如果存在则从缓存中取数据。Iterate查询出来的对象也会放入缓存。
一级缓存存的是对象,属性是不会存的。
当然一级缓存的内存是有限的,什么数据都往里面存,所以我们需要管理一级缓存,通过flush(),clear(),evict()。
通过查阅Hibernate的API可以知道flush方法的主要作用就是清理缓存,强制数据库与Hibernate缓存同步,以保证数据的一致性。它的主要动作就是向数据库发送一系列的sql语句,并执行这些sql语句,但是不会向数据库提交。而commit方法则会首先调用flush方法,然后提交事务。这就是为什么我们仅仅调用flush的时候记录并未插入到数据库中的原因,因为只有提交了事务,对数据库所做的更新才会被保存下来。因为commit方法隐式的调用了flush,所以一般我们都不会显示的调用flush方法。
二级缓存又称为SessionFactory缓存,是进程级别的缓存,可以跨越Session存在,可以被多个Session所共享。支持集群。二级缓存是可选的。二级缓存的介质可以是内存或者硬盘
适合放到二级缓存中:
(1)经常被访问
(2)改动不大
(3)数量有限
(4)不是很重要的数据,允许出现偶尔并发的数据。
这样的数据非常适合放到二级缓存中的。
使用步骤:
1 . 在hibernate.cfg.xml中配置二级缓存
<property name="hibernate.cache.use_second_level_cache">trueproperty>
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProviderproperty>
在hibernate4以后的配置
<property name="cache.use_second_level_cache">trueproperty>
<property name="cache.region.factory_class">
org.hibernate.cache.ehcache.EhCacheRegionFactoryproperty>
2 . 导入ehcache.jar等相关jar包
3 . 将ehcahe.xml放入src下(在project→etc下找)
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd">
<diskStore path="java.io.tmpdir" />
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU" />
ehcache>
4.在类中指定或在(hibernate.cfg.xml)指定
类中(*.hbm.xml中)
<hibernate-mapping>
<class name="cn.siggy.pojo.Book" table="book" catalog="hibernate4">
<cache usage="read-only"/>
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="identity" />
id>
<property name="author" type="java.lang.String">
<column name="author" />
property>
<property name="name" type="java.lang.String">
<column name="name" />
property>
<property name="price" type="java.lang.Double">
<column name="price" precision="22" scale="0" not-null="true" />
property>
<property name="pubDate" type="java.sql.Timestamp">
<column name="pubDate" length="19" />
property>
class>
hibernate-mapping>
在hibernate.cfg.xml中指定类 配置
<class-cache usage="read-only" class="cn.siggy.pojo.Book"/>
5 .测试使用
@Test
public void testGet(){
Session session = HibernateUtil.getSession();
Transaction tx = session.beginTransaction();
Book book = (Book)session.get(Book.class, 1);
//发出sql语句取数据
System.out.println(book.getName());
HibernateUtil.closeSession();
session = HibernateUtil.getSession();
System.out.println("---------");
//因为有二级缓存,尽管上传查询关闭session但是这里没有发出sql语句
book = (Book)session.get(Book.class, 1);
System.out.println(book.getName());
tx.commit();
HibernateUtil.closeSession();
}
查询数据的时候会先放入一级缓存,然后拷贝一份到二级缓存中去
查询缓存 在二级缓存的基础上来的,所以我们要使用查询缓存也就是要先配置好二级缓存。
在hibernate.cfg.xml中配置
<property name="cache.use_query_cache">trueproperty>
hibernate的查询缓存是主要是针对普通属性结果集的缓存
如下测试使用
List list = session.createQuery("from Book")
.setCacheable(true)//使用查询缓存
.list();
System.out.println(list.size());
System.out.println("=========================");
session.close();
session = HibernateUtil.getSession();
list = session.createQuery("from Book")
.setCacheable(true)//使用查询缓存
.list();
System.out.println(list.size());
这里只会发出一条sql语句,之前说过list查询是不会去缓存中找的,但是会把查询到的对象放入到缓存。这里设置了查询缓存后list就会先去缓存中找数据,hibernate的查询缓存是主要是针对普通属性结果集的缓存