名扬数据Hibernate的缓存解读

对数据库中的数据复制一份临时放在内存中的容器,缓存是介于物理数据源与应用顺序之间。其作用是为了减少应用顺序对物理数据源访问的次数,从而提高了应用的运行性能。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>