对数据库中的数据复制一份临时放在内存中的容器,缓存是介于物理数据源与应用顺序之间。其作用是为了减少应用顺序对物理数据源访问的次数,从而提高了应用的运行性能。Hibern进行读取数据的时候,根据缓存机制在相应的缓存中查询,如果在缓存中找到需要的数据(把这称做“缓存命中"则就直接把命中的数据作为结果加以利用,防止了大量发送SQL语句到数据库查询的性能损耗。
Hibern缓存分类:
一、Session缓存(又称作事务缓存)Hibern内置的不能卸除。
当Session被关闭后,缓存范围:缓存只能被当前Session对象访问。缓存的生命周期依赖于Session生命周期。缓存也就结束生命周期。
可插拔。二、SessionFactori缓存(又称作应用缓存)使用第三方插件。
因此必需对缓存进行更新。缓存的生命周期依赖于应用的生命周期,缓存范围:缓存被应用范围内的所有session共享。这些session有可能是并发访问缓存。应用结束时,缓存也就结束了生命周期,二级缓存存在于应用顺序范围。
Hibern一些与一级缓存相关的操作(时间点)
数据放入缓存:
该对象会被放入到session缓存中。1.save当session对象调用save方法保管一个对象后。
该对象也会被放入到session缓存中。2.get和load当session对象调用get或load方法从数据库取出一个对象后。
3.使用HQL和QBC等从数据库中查询数据。
例如:数据库有一张表如下:
使用get或load证明缓存的存在
publicclassClient
{
publicstaticvoidmainString[]arg
{
Sessionsession=HibernateUtil.getSessionFactori.openSess;
Transacttx=null;
try
{
/*开启一个事务*/
tx=session.beginTransact;
/*从数据库中获取id="402881e534fa5a440134fa5a45340002"Custom对象*/
"402881e534fa5a440134fa5a45340002"; Customcustomer1=Customsession.getCustomer.class.
System.out.println"customer.getUsernamis"+customer1.getUsernam;
/*事务提交*/
tx.commit;
System.out.println"-------------------------------------";
/*开启一个新事务*/
tx=session.beginTransact;
/*从数据库中获取id="402881e534fa5a440134fa5a45340002"Custom对象*/
"402881e534fa5a440134fa5a45340002"; Customcustomer2=Customsession.getCustomer.class.
System.out.println"customer2.getUsernamis"+customer2.getUsernam;
/*事务提交*/
tx.commit;
System.out.println"-------------------------------------";
/*比较两个get方法获取的对象是否是同一个对象*/
System.out.println"customer1==customer2resultis"+customer1==customer2;
}
catchExceptione
{
iftx!=null
{
tx.rollback;
}
}
final
{
session.clos;
}
}
}
顺序控制台输出结果:
Hibernate:
select
customer0_.idasid0_0_.
customer0_.usernamasusername0_0_.
customer0_.balasbalance0_0_
from
customcustomer0_
where
customer0_.id=?
customer.getUsernamislisi
-------------------------------------
customer2.getUsernamislisi
-------------------------------------
customer1==customer2resultistrue
而且customer1==customer2resultistrue说明两个取出来的对象是同一个对象。其原理是第一次调用get方法,输出结果中只包含了一条SELECTSQL语句。Hibern先检索缓存中是否有该查找对象,发现没有,Hibern发送SELECT语句到数据库中取出相应的对象,然后将该对象放入缓存中,以便下次使用,第二次调用get方法,Hibern先检索缓存中是否有该查找对象,发现正好有该查找对象,就从缓存中取出来,不再去数据库中检索。
数据从缓存中清除:
释放对象所占用的内存资源,1.evit将指定的耐久化对象从缓存中清除。指定对象从耐久化状态变为脱管状态,从而成为游离对象。
释放其占用的内存资源。2.clear将缓存中的所有耐久化对象清除。
其他缓存操作:
1.contain判断指定的对象是否存在于缓存中。
使之与数据库数据坚持同步。2.flush刷新缓存区的内容。
Hibern使用二级缓存
适合存放到第二级缓存中的数据:
1.很少被修改的数据。
允许出现偶尔并发的数据。2.不是很重要的数据。
3.不会被并发访问的数据。
实例数目有限,实例会被许多其他类的实例引用,实例极少或者历来不会被修改。4.参考数据,指的供应用参考的常量数据。
不适合存放到第二级缓存的数据:
1.经常被修改的数据。
绝对不允许出现并发。2.财务数据。
3.与其他应用共享的数据。
可以把缓存看做是一个Map对象,Hibern如何将数据库中的数据放入到二级缓存中?注意。Kei用于存储对象OIDValu用于存储POJO首先,当我使用Hibern从数据库中查询出数据,获取检索的数据后,Hibern将检索出来的对象的OID放入缓存中kei中,然后将具体的POJO放入valu中,等待下一次再次向数据查询数据时,Hibern根据你提供的OID先检索一级缓存,若没有且配置了二级缓存,则检索二级缓存,如果还没有则才向数据库发送SQL语句,然后将查询出来的对象放入缓存中。
为Hibern配置二级缓存:
主配置文件中hibernate.cfg.xml
<propertiname="hibernate.cache.use_second_level_cache">true</property>
<propertiname="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
配置ehcache.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<ehcache>
<!--
缓存到硬盘的路径
-->
<diskStorpath="d:/ehcache"></diskStore>
<!--
默认设置
maxElementsInMemori:內存中最大緩存的对象数量。
etern:缓存的对象是否永远不变。
timeToIdleSecond可以操作对象的时间。
时间到后查询数据会从数据库中读取。 timeToLiveSecond缓存中对象的生命周期。
overflowToDisk内存满了否要缓存到硬盘。
-->
<defaultCachmaxElementsInMemory="200"eternal="false"
timeToIdleSeconds="50"timeToLiveSeconds="60"overflowToDisk="true"></defaultCache>
<!--
指定缓存的对象。
下面呈现的属性覆盖上面呈现的没出现的继承上面的
-->
<cachname="com.suxiaolei.hibernate.pojos.Order"maxElementsInMemory="200"eternal="false"
timeToIdleSeconds="50"timeToLiveSeconds="60"overflowToDisk="true"></cache>
</ehcache>
需要被缓存的对象中hbm文件中的<class>标签下添加一个<cache>子标签
<hibernate-mapping>
<classname="com.suxiaolei.hibernate.pojos.Order"table="orders">
<cachusage="read-only"/>
<idname="id"type="string">
<columnname="id"></column>
<generclass="uuid"></generator>
</id>
<propertiname="orderNumber"column="orderNumber"type="string"></property>
<propertiname="cost"column="cost"type="integer"></property>
<many-to-onname="customer"class="com.suxiaolei.hibernate.pojos.Customer"
column="customer_id"cascade="save-update">
</many-to-one>
</class>
</hibernate-mapping>
想要在获取一方的时候将关联的多方缓存起来,若存在一对多的关系。需要再集合属性下添加<cache>子标签,这里需要将关联的对象的hbm文件中必须在存在<class>标签下也添加<cache>标签,不然Hibern只会缓存OID
<hibernate-mapping>
<classname="com.suxiaolei.hibernate.pojos.Customer"table="customer">
<!--主键设置 -->
<idname="id"type="string">
<columnname="id"></column>
<generclass="uuid"></generator>
</id>
<!--属性设置 -->
<propertiname="username"column="username"type="string"></property>
<propertiname="balance"column="balance"type="integer"></property>
<setname="orders"inverse="true"cascade="all"lazy="false"fetch="join">
<cachusage="read-only"/>
<keicolumn="customer_id"></key>
<one-to-maniclass="com.suxiaolei.hibernate.pojos.Order"/>
</set>
</class>