现在的位置: 首页 > 综合 > 正文

hibernate 之 对象状态/缓存

2017年11月22日 ⁄ 综合 ⁄ 共 3404字 ⁄ 字号 评论关闭

在持久化层角度上说,一个java对象在生命周期中可以处于四个状态:

1. 临时状态(Transient):刚用new创建的对象,未被持久化,此时并没有处于Session缓存中

2. 持久化状态(Persistent):已经持久化,加入到了Session缓存中。

3. 游离状态(Detached):已经被持久化,但不再处于Session缓存中,此时数据库中依旧有记录

4. 删除状态(removed):不再处于Session缓存中,并且已经计划将其从数据库中删除。

下图是上述四种状态的描述:


 缓存(Session/SessionFactoy)

Session 缓存是hibernate的第一级缓存,由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存,这一级缓存是必须的。

第二级缓存默认的情况下是打开的,由SessionFactoy管理,由于SessionFactory对象的生命周期和应用程序的整个进程对应,因此第二级缓存是进程范围或集群范围的缓存

SessionFactory对象的创建代价很昂贵,线程安全,它为所有的应用程序线程所共享。它只创建一次,通常是在应用程序启动的时候,由一个 Configuraion 的实例来创建。

一级缓存:

Session 对象的创建代价比较小,是非线程安全的,对于单个请求,单个会话、单个的 工作单元而言,它只被使用一次,然后就丢弃。只有在需要的时候,一个 Session 对象 才会获取一个 JDBC 的 Connection(或一个Datasource)对象,因此假若不使用的时候它不消费任何资源。

得到Session的方法有如下两个:
openSession :每次都是新的Session,并且要手动close
getCurrentSession:从上下文找,如已有那么用已经有的Session,如没有,创建新的;不需要手动close,当一个线程提交或撤销事务后hibernate自动关闭session对象;

<property name=”current_session_context_class”>thread</property>
current_session_context_class有四个值,两个是常用的:

thread:在线程里找是否有已经存在的Session(getCurrentSession());(最常用)
jta:主要针对数据库分布式而用;(处理多个数据库事务)

 Transaction tx=session.beginTransaction();
 //第一次执行get方法,先到Session 缓存中查找oid为1的User对象,由于不存在这样的对象,要向数据库查询,
 User u1=(User)session.get(User.class, new Long(1));
 //第二次执行,由于在缓存中查找时能找到,故不再向数据库中执行sql语句
 User u2=(User)session.get(User.class, new Long(1));
 System.out.println(u2==u1);//true
 tx.commit();

二级缓存:

不是所有的数据都适合放在二级缓存中

下面这几种情况就不适合加载到二级缓存中: 

  1. 经常被修改的数据 
  2. 绝对不允许出现并发访问的数据
  3. 与其他应用共享的数据 

下面这己种情况合适加载到二级缓存中: 

  1.   数据更新频率低 
  2.   允许偶尔出现并发问题的非重要数据 
  3.   不会被并发访问的数据 
  4.   常量数据 
  5.   不会被第三方修改的数据 

二级缓存功能是配置二级缓存插件来实现的,有org.hibernate.cache.CacheProvider借口,它充当缓存插件与Hibernate之间的适配器 . 
常用的二级缓存插件 
EHCache  org.hibernate.cache.EhCacheProvider 
OSCache  org.hibernate.cache.OSCacheProvider 
SwarmCahe  org.hibernate.cache.SwarmCacheProvider 
JBossCache  org.hibernate.cache.TreeCacheProvider 


load、iterate默认使用二级缓存;

list默认往二级缓存加数据,但是查询的时候不使用,如果query用二级缓存,需打开查询缓存,只有查询条件一样时才会调用二级缓存

<property name="cache.use_query_cache">true</property> <!--查询缓存 -->

调用query的setCachable(true)方法指明使用二级缓存

如果配置了查询缓存,以下代码只发送一次sql请求:

public void testQueryCache() {
	Session session = sf.openSession();
	session.beginTransaction();
	List<Category> categories = (List<Category>)session.createQuery("from Category").setCacheable(true).list();
	session.getTransaction().commit();
	session.close();
		
	Session session2 = sf.openSession();
	session2.beginTransaction();
	List<Category> categories2 = (List<Category>)session2.createQuery("from Category").setCacheable(true).list();
	session2.getTransaction().commit();
	session2.close();
}

EHCache的配置 hibernate.cfg.xml 

<hibernate-configuration>  
   <session-factory>  
      <!-- 设置二级缓存插件EHCache的Provider类-->  
      <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>  
      <!-- 启动"查询缓存" -->  
      <property name="hibernate.cache.use_query_cache">true</property>  
   </session-factory>  
 </hibernate-configuration>  

ehcache.xml 

<ehcache>  
  <!-- maxElementsInMemory为缓存对象的最大数目, eternal设置是否永远不过期,timeToIdleSeconds对象处于空闲状态的最多秒数,timeToLiveSeconds对象处于缓存状态的最多秒数 -->  
  <diskStore path="java.io.tmpdir"/>  
    <defaultCache maxElementsInMemory="10000" eternal="false"  timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true"/>  
</ehcache>  

****.hbm.xml 

<hibernate-mapping>      
   <class>  
       <!-- 设置该持久化类的二级缓存并发访问策略 read-only read-write nonstrict-read-write transactional-->  
       <cache usage="read-write"/>      
   </class>  
</hibernate-mapping>  

二级缓存也可以用annotation配置:http://docs.jboss.org/hibernate/annotations/3.4/reference/zh_cn/html_single/

缓存算法有:
LRU(Least Recently Used)、LFU(Least Frequently Used)、FIFO(First In First Out)
使用时通常在缓存配置文件中加入:MemoryStoreEvictionPolicy="LRU"

抱歉!评论已关闭.