Hibernate的缓存解读

开发 后端
缓存是介于物理数据源与应用程序之间,是对数据库中的数据复制一份临时放在内存中的容器,其作用是为了减少应用程序对物理数据源访问的次数,从而提高了应用的运行性能。

缓存是介于物理数据源与应用程序之间,是对数据库中的数据复制一份临时放在内存中的容器,其作用是为了减少应用程序对物理数据源访问的次数,从而提高了应用的运行性能。Hibernate在进行读取数据的时候,根据缓存机制在相应的缓存中查询,如果在缓存中找到了需要的数据(我们把这称做“缓存命中"),则就直接把命中的数据作为结果加以利用,避免了大量发送SQL语句到数据库查询的性能损耗。

Hibernate缓存分类:

一、Session缓存(又称作事务缓存):Hibernate内置的,不能卸除。

缓存范围:缓存只能被当前Session对象访问。缓存的生命周期依赖于Session的生命周期,当Session被关闭后,缓存也就结束生命周期。

二、SessionFactory缓存(又称作应用缓存):使用第三方插件,可插拔。

缓存范围:缓存被应用范围内的所有session共享。这些session有可能是并发访问缓存,因此必须对缓存进行更新。缓存的生命周期依赖于应用的生命周期,应用结束时,缓存也就结束了生命周期,二级缓存存在于应用程序范围。

Hibernate一些与一级缓存相关的操作(时间点):

数据放入缓存:

1. save()。当session对象调用save()方法保存一个对象后,该对象会被放入到session的缓存中。

2. get()和load()。当session对象调用get()或load()方法从数据库取出一个对象后,该对象也会被放入到session的缓存中。

3. 使用HQL和QBC等从数据库中查询数据。

例如:数据库有一张表如下:

使用get()或load()证明缓存的存在:

  1. public class Client  
  2. {  
  3.     public static void main(String[] args)  
  4.     {  
  5.         Session session = HibernateUtil.getSessionFactory().openSession();  
  6.         Transaction tx = null;  
  7.         try 
  8.         {  
  9.             /*开启一个事务*/ 
  10.             tx = session.beginTransaction();  
  11.             /*从数据库中获取id="402881e534fa5a440134fa5a45340002"的Customer对象*/ 
  12.             Customer customer1 = (Customer)session.get(Customer.class"402881e534fa5a440134fa5a45340002");  
  13.             System.out.println("customer.getUsername is"+customer1.getUsername());  
  14.             /*事务提交*/ 
  15.             tx.commit();  
  16.               
  17.             System.out.println("-------------------------------------");  
  18.               
  19.             /*开启一个新事务*/ 
  20.             tx = session.beginTransaction();  
  21.             /*从数据库中获取id="402881e534fa5a440134fa5a45340002"的Customer对象*/ 
  22.             Customer customer2 = (Customer)session.get(Customer.class"402881e534fa5a440134fa5a45340002");  
  23.             System.out.println("customer2.getUsername is"+customer2.getUsername());  
  24.             /*事务提交*/ 
  25.             tx.commit();  
  26.               
  27.             System.out.println("-------------------------------------");  
  28.               
  29.             /*比较两个get()方法获取的对象是否是同一个对象*/ 
  30.             System.out.println("customer1 == customer2 result is "+(customer1==customer2));  
  31.         }  
  32.         catch (Exception e)  
  33.         {  
  34.             if(tx!=null)  
  35.             {  
  36.                 tx.rollback();  
  37.             }  
  38.         }  
  39.         finally 
  40.         {  
  41.             session.close();  
  42.         }  
  43.     }  

程序控制台输出结果:

  1. Hibernate:   
  2.     select  
  3.         customer0_.id as id0_0_,  
  4.         customer0_.username as username0_0_,  
  5.         customer0_.balance as balance0_0_   
  6.     from  
  7.         customer customer0_   
  8.     where  
  9.         customer0_.id=?  
  10. customer.getUsername islisi  
  11. -------------------------------------  
  12. customer2.getUsername islisi  
  13. -------------------------------------  
  14. customer1 == customer2 result is true 

输出结果中只包含了一条SELECT SQL语句,而且customer1 == customer2 result is true说明两个取出来的对象是同一个对象。其原理是:***次调用get()方法, Hibernate先检索缓存中是否有该查找对象,发现没有,Hibernate发送SELECT语句到数据库中取出相应的对象,然后将该对象放入缓存中,以便下次使用,第二次调用get()方法,Hibernate先检索缓存中是否有该查找对象,发现正好有该查找对象,就从缓存中取出来,不再去数据库中检索。

数据从缓存中清除:

1. evit()将指定的持久化对象从缓存中清除,释放对象所占用的内存资源,指定对象从持久化状态变为脱管状态,从而成为游离对象。

2. clear()将缓存中的所有持久化对象清除,释放其占用的内存资源。

其他缓存操作:

1. contains()判断指定的对象是否存在于缓存中。

2. flush()刷新缓存区的内容,使之与数据库数据保持同步。

 

Hibernate使用二级缓存

适合存放到第二级缓存中的数据:

1. 很少被修改的数据。

2. 不是很重要的数据,允许出现偶尔并发的数据。

3. 不会被并发访问的数据。

4. 参考数据,指的是供应用参考的常量数据,它的实例数目有限,它的实例会被许多其他类的实例引用,实例极少或者从来不会被修改。

不适合存放到第二级缓存的数据:

1. 经常被修改的数据。

2. 财务数据,绝对不允许出现并发。

3. 与其他应用共享的数据。

Hibernate如何将数据库中的数据放入到二级缓存中?注意,你可以把缓存看做是一个Map对象,它的Key用于存储对象OID,Value用于存储POJO。首先,当我们使用Hibernate从数据库中查询出数据,获取检索的数据后,Hibernate将检索出来的对象的OID放入缓存中key中,然后将具体的POJO放入value中,等待下一次再次向数据查询数据时,Hibernate根据你提供的OID先检索一级缓存,若没有且配置了二级缓存,则检索二级缓存,如果还没有则才向数据库发送SQL语句,然后将查询出来的对象放入缓存中。

为Hibernate配置二级缓存:

在主配置文件中hibernate.cfg.xml

  1. <property name="hibernate.cache.use_second_level_cache">true</property> 
  2. <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property> 

配置ehcache.xml

  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <ehcache> 
  3.     <!--  
  4.         缓存到硬盘的路径  
  5.     --> 
  6.     <diskStore path="d:/ehcache"></diskStore> 
  7.       
  8.     <!--  
  9.         默认设置  
  10.         maxElementsInMemory : 在內存中***緩存的对象数量。  
  11.         eternal : 缓存的对象是否永远不变。  
  12.         timeToIdleSeconds :可以操作对象的时间。  
  13.         timeToLiveSeconds :缓存中对象的生命周期,时间到后查询数据会从数据库中读取。  
  14.         overflowToDisk :内存满了,是否要缓存到硬盘。  
  15.     --> 
  16.     <defaultCache maxElementsInMemory="200" eternal="false"   
  17.         timeToIdleSeconds="50" timeToLiveSeconds="60" overflowToDisk="true"></defaultCache> 
  18.           
  19.     <!--  
  20.         指定缓存的对象。  
  21.         下面出现的的属性覆盖上面出现的,没出现的继承上面的。  
  22.     --> 
  23.     <cache name="com.suxiaolei.hibernate.pojos.Order" maxElementsInMemory="200" eternal="false"   
  24.         timeToIdleSeconds="50" timeToLiveSeconds="60" overflowToDisk="true"></cache> 
  25.  
  26. </ehcache> 

在需要被缓存的对象中hbm文件中的<class>标签下添加一个<cache>子标签

  1. <hibernate-mapping> 
  2.     <class name="com.suxiaolei.hibernate.pojos.Order" table="orders"> 
  3.         <cache usage="read-only"/> 
  4.           
  5.         <id name="id" type="string"> 
  6.             <column name="id"></column> 
  7.             <generator class="uuid"></generator> 
  8.         </id> 
  9.           
  10.         <property name="orderNumber" column="orderNumber" type="string"></property> 
  11.         <property name="cost" column="cost" type="integer"></property> 
  12.           
  13.         <many-to-one name="customer" class="com.suxiaolei.hibernate.pojos.Customer"   
  14.                      column="customer_id" cascade="save-update"> 
  15.         </many-to-one>          
  16.     </class> 
  17. </hibernate-mapping> 

若存在一对多的关系,想要在在获取一方的时候将关联的多方缓存起来,需要再集合属性下添加<cache>子标签,这里需要将关联的对象的hbm文件中必须在存在<class>标签下也添加<cache>标签,不然Hibernate只会缓存OID。

  1. <hibernate-mapping> 
  2.         <class name="com.suxiaolei.hibernate.pojos.Customer" table="customer"> 
  3.             <!-- 主键设置 --> 
  4.             <id name="id" type="string"> 
  5.                 <column name="id"></column> 
  6.                 <generator class="uuid"></generator> 
  7.             </id> 
  8.               
  9.             <!-- 属性设置 --> 
  10.             <property name="username" column="username" type="string"></property> 
  11.             <property name="balance" column="balance" type="integer"></property> 
  12.               
  13.             <set name="orders" inverse="true" cascade="all" lazy="false" fetch="join"> 
  14.                 <cache usage="read-only"/> 
  15.                 <key column="customer_id" ></key> 
  16.                 <one-to-many class="com.suxiaolei.hibernate.pojos.Order"/> 
  17.             </set> 
  18.               
  19.         </class> 
  20.     </hibernate-mapping> 

原文链接:http://www.cnblogs.com/otomedaybreak/archive/2012/01/20/2328317.html

【编辑推荐】

  1. Hibernate的集合映射
  2. Hibernate关联关系配置
  3. Hibernate中inverse属性与cascade属性
  4. Hibernate复合主键映射
  5. Hibernate继承映射
责任编辑:林师授 来源: 音①晓的博客
相关推荐

2009-09-25 16:29:32

Hibernate一级

2009-06-29 08:48:41

Hibernate缓存

2009-09-22 10:50:04

Hibernate c

2009-09-25 13:51:13

Hibernate S

2009-09-25 10:25:54

Hibernate缓存

2009-06-18 14:51:12

Hibernate缓存Hibernate

2009-06-17 15:43:03

Hibernate缓存

2009-09-23 17:03:08

Hibernate S

2009-09-25 14:20:28

Hibernate继承映射

2009-09-25 09:46:02

Hibernate高级

2009-09-22 11:24:07

Hibernate查询

2009-06-30 14:08:00

Hibernate缓存

2009-06-17 15:52:23

Hibernate查询

2009-06-17 15:13:30

2009-09-27 14:53:38

Hibernate S

2009-06-30 14:11:00

Hibernate缓存

2010-07-12 17:12:37

JPA 2.0缓存Hibernate缓存Java EE

2009-09-28 09:47:55

Hibernate数据

2012-02-08 11:01:53

HibernateJava

2010-07-13 16:20:18

JPA 2.0缓存Hibernate缓存Java EE
点赞
收藏

51CTO技术栈公众号