1. 程式人生 > >JPA Cache快取

JPA Cache快取

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

先了解一下cache基礎:

一級快取

Hibernate 的一級快取是由 Session 提供的,因此它只存在於 Session 的生命週期中,當程式呼叫 save(),update(),saveorupdate() 等方法 及呼叫查詢介面 list,filter,iterate 時,如 session 快取中還不存在相應的物件, Hibernate 會把該物件加入到一級快取中,
當 Session 關閉的時候該 Session 所管理的一級快取也會立即被清除
Hibernate 的一級快取是 Session 所內建的,不能被解除安裝,也不能進行任何配置
 
二級快取配置:    
  
1 、首先要開啟二級快取,在 hibernate.cfg.xml 中新增如下配置:    
<property name="hibernate.cache.use_second_level_cache">true</property>  
  
2 、 Hibernate 的二級快取使用第三方的快取工具來實現,所以我們需要指定 Hibernate 使用哪個    
   快取工具。如下配置指定 Hibernate 使用 EhCache 快取工具。    
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>  
  
3 、 Hibernate 在預設情況下並不會對所有實體物件進行快取,所以,我們需要指定快取哪些物件,    
在實體物件的對映檔案中(相應的 <class> 標籤內部),新增如下配置:    
<cache usage="read-only"/>  
  
usage="read-only" 是“只讀”快取策略。    
  
注意,這個 <cache> 標籤只能放在 <class> 標籤的內部,而且必須處在 <id> 標籤的前面!!!    
這個 <cache> 標籤放在哪些 <class> 標籤下面,就說明會多這些類的物件進行快取    
  
4 、對於第 3 步,有一個可選的方案是在 hibernate.cfg.xml 檔案中指定哪些類的物件需要快取,    
   而不需要使用 <cache> 標籤來指定。如:    
   在 hibernate.cfg.xml 中新增如下配置:    
   <class-cache class="com.bjsxt.hibernate.Classes" usage="read-only" />  
     
   注意,這個 <class-cache> 標籤必須放在 <mapping> 標籤的後面!!    
 
Hibernate快取配置
_____________________________________________________________________________________
Hibernate的快取分為:
  一級快取:在Session級別的,在Session關閉的時候,一級快取就失效了。
  二級快取:在SessionFactory級別的,它可以使用不同的快取實現,如EhCache 、JBossCache、OsCache等。
  
快取的註釋寫法如下,加在Entity的java類上:
  @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
  
快取的方式有四種,分別為:
  CacheConcurrencyStrategy.NONE
  CacheConcurrencyStrategy.READ_ONLY,只讀模式,在此模式下,如果對資料進行更新操作,會有異常;
  CacheConcurrencyStrategy.READ_WRITE,讀寫模式在更新快取的時候會把快取裡面的資料換成一個鎖,其它事務如果去取相應的快取資料,發現被鎖了,直接就去資料庫查詢;
  CacheConcurrencyStrategy.NONSTRICT_READ_WRITE,不嚴格的讀寫模式則不會的快取資料加鎖;
  CacheConcurrencyStrategy.TRANSACTIONAL,事務模式指快取支援事務,當事務回滾時,快取也能回滾,只支援JTA環境。
  
另外還有如下注意事項:
  1、查詢快取需要在Query的相應方法執行前加上這麼一句:
  query.setCacheable(true);
  在使用Hibernate時,獲得的query有setCacheable 方法,可以設定使用快取,但當使用JPA時,javax.persistence.Query並沒有setCacheable方法,此時如果JPA的實現是Hibernate時,可以將其進行如下轉化,再呼叫setCacheable方法(如果JPA的實現是其它ORMAP框架,就不知道怎麼做了)。
if (query instanceof org.hibernate.ejb.QueryImpl) {
    ((org.hibernate.ejb.QueryImpl) query).getHibernateQuery().setCacheable(true);
}
  2、還有就是查詢快取的查詢執行後,會將查詢結果放入二級快取中,但是放入的形式是以ID為Key,例項作為一個Value。
  3、hibernate的配置檔案中需加入如下資訊:
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider" />
<property name="hibernate.cache.use_second_level_cache" value="true" />
<property name="hibernate.cache.use_query_cache" value="true" />
 


快取對映(Cache mappings)

類或者集合對映的“<cache> 元素”可以有下列形式:

<cache

 usage="transactional|read-write|nonstrict-read-write|read-only" (1)

/>
(1)
usage 說明了快取的策略: transactional 、 read-write 、 nonstrict-read-write 或 read-only 。 

另外(首選?), 你可以在hibernate.cfg.xml中指定<class-cache> 和 <collection-cache> 元素。
這裡的usage 屬性指明瞭快取並 發策略(cache concurrency strategy) 。


只讀 快取(read only)

如果你的應用程式只需讀取一個持久化類的例項,而無需對其修改, 那麼就可以對其進行只讀 快取。這是最簡單,也是實用性最好的方法。甚至在叢集中,它也能完美地運作。
<class name="eg.Immutable" mutable="false">

 <cache usage="read-only"/>

 ....

</class>

 


讀/寫快取( read/write)

如果應用程式需要更新資料,那麼使用讀/寫快取 比較合適。 如果應用程式要求“序列化事務”的隔離級別(serializable transaction isolation level),那麼就決不能使用這種快取策略。 如果在JTA環境中使用快取,你必須指定hibernate.transaction.manager_lookup_class 屬 性的值, 通過它,Hibernate才能知道該應用程式中JTA的TransactionManager 的 具體策略。 在其它環境中,你必須保證在Session.close() 、或Session.disconnect() 呼叫前, 整個事務已經結束。 如果你想在叢集環境中使用此策略,你必須保證底層的快取實現支援鎖定(locking)。Hibernate內建的快取策略並不支援鎖定功能。
<class name="eg.Cat" .... >

 <cache usage="read-write"/>

 ....

 <set name="kittens" ... >

 <cache usage="read-write"/>

 ....

 </set>

</class>

非嚴格讀/寫快取(nonstrict read/write)

如果應用程式只偶爾需要更新資料(也就是說,兩個事務同時更新同一記錄的情況很不常見),也不需要十分嚴格的事務隔離, 那麼比較適合使用非嚴格讀/寫快取 策略。如果在JTA環境中使用該策略, 你必須為其指定hibernate.transaction.manager_lookup_class 屬性的值, 在其它環境中,你必須保證在Session.close() 、或Session.disconnect() 呼叫前, 整個事務已經結束

-------------------------------------------------------------------------
在jBPM 中使用不少這樣的非嚴格讀/寫快取的處理:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd ">
<hibernate-mapping default-access="field">
  <class name="org.jbpm.context.def.VariableAccess"
         table="JBPM_VARIABLEACCESS"
         lazy="false">
    <cache usage="nonstrict-read-write"/>
    <id name="id" column="ID_"><generator class="native" /></id>
   
    <property name="variableName" column="VARIABLENAME_" />
    <property name="access" column="ACCESS_" />
    <property name="mappedName" column="MAPPEDNAME_" />
  </class>
</hibernate-mapping>

它的ehcache.xml 是這樣配置的:
<ehcache>
 <defaultCache
        maxElementsInMemory="100000"
        eternal="true"
        overflowToDisk="false"
        diskPersistent="false"
        />
</ehcache>
 
Hibernate Annotation 中配置EhCache快取


1.  首先設定EhCache,建立配置檔案ehcache.xml,預設的位置在class-path,可以放到你的src目錄下:

xml  version ="1.0"  encoding ="UTF-8" ?>   
< ehcache >   
 < diskStore  path ="java.io.tmpdir" />     
  < defaultCache   
   maxElementsInMemory ="10000"    
   eternal ="false"    
  
   overflowToDisk ="true"    
  
   timeToIdleSeconds ="300"    
   timeToLiveSeconds ="180"    
   diskPersistent ="false"   
   diskExpiryThreadIntervalSeconds = "120" />     
ehcache >   

  2.  在Hibernate配置檔案中設定:

<hibernate-configuration> <session-factory> ……<property name=" hibernate . cache.provider_class">org.hibernate.cache.EhCacheProvider </property> <property name="cache.use_second_level_cache">true </property> ……</session-factory> </hibernate-configuration> 
        此外,可以把cache.use_second_level_cache設定為false關閉所有的hibernate二級快取。但此屬性對指定<cache>的類預設為true。

 
   3.  為了使用二級快取,需要在每一個Hibernate Entity上配置。

@Entity   
@Cache (usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)   
public   class  Forest { ... }  


@OneToMany (cascade=CascadeType.ALL, fetch=FetchType.EAGER)   
@JoinColumn (name= "CUST_ID" )   
@Cache (usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)   
public  SortedSet getTickets() {   
     return  tickets;   
}  


@Cache (   
    CacheConcurrencyStrategy usage();                 (1 )   
    String region()  default   "" ;                       (2 )   
    String include()  default   "all" ;                   (3 )   
)  


(1) usage: 提供快取物件的事務隔離機制,可選值有以下幾種
(NONE, READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL)
(2) region (optional): 指定快取的區域,預設是類的全限定名。利用快取區域,可以更精確的指定每個區域的快取超前策略。如果指定了快取區域字首(在 hibernate.cfg.xml中設定cache.region_prefix屬性為一個字串),則所有的快取區域名前將加上這個字首。
(3) include (optional): all to include all properties, non-lazy to only include non lazy properties (default all).
如果不是使用annotation的話,則是在Hbm檔案中新增cache usage="read-only"

---------------------------------------------

本次專案使用hibernate + jpa, 其配置如下:

jap的persistence.xml檔案

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
    version="1.0">   
    <persistence-unit name="punit" transaction-type="RESOURCE_LOCAL">
        <provider >org.hibernate.ejb.HibernatePersistence</provider>
        <mapping-file>IptvFeeORM.xml</mapping-file>
        <properties>
            <property name="hibernate.jdbc.batch_size" value="100"/>
            <property name="hibernate.cache.use_second_level_cache"
                      value="true" />
              <property name="hibernate.cache.provider_class"
                  value="net.sf.ehcache.hibernate.EhCacheProvider" />
              <property name="hibernate.cache.use_minimal_puts" value="true"/>
            <property name="net.sf.ehcache.configurationResourceName" value="/hibernate_ehcache.xml"/>
        </properties>
    </persistence-unit>
</persistence>

cache.xml配置檔案:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <diskStore path="./ehcache/hibernate/diskStore" />
    <defaultCache maxElementsInMemory="5000000" eternal="false"
        timeToIdleSeconds="600" timeToLiveSeconds="600" overflowToDisk="false"
        diskPersistent="false" diskExpiryThreadIntervalSeconds="1200"
        memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>

spring引用的資料庫配置檔案 IptvFeeConfig.properties :

#database config
jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@192.168.1.1:1521:love
jdbc.username=you
jdbc.password=me
jdbc.maxActive=5
jdbc.maxIdle=5
jpa.database=ORACLE
jpa.showSql=true
jpa.generateDdl=false
jdbc.getdate.sql=select sysdate from dual

spring 裡面的配置檔案:

<bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:IptvFeeConfig.properties" />
    </bean>
    <bean
        class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="persistenceXmlLocation" value="classpath:IptvFeePersistence.xml" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="database" value="${jpa.database}" />
                <property name="showSql" value="${jpa.showSql}" />
                <property name="generateDdl" value="${jpa.generateDdl}"></property>
                <property name="databasePlatform" value="org.hibernate.dialect.OracleDialect" />
            </bean>
        </property>
    </bean>
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName">
            <value>${jdbc.driver}</value>
        </property>
        <property name="url">
            <value>${jdbc.url}</value>
        </property>
        <property name="username">
            <value>${jdbc.username}</value>
        </property>
        <property name="password">
            <value>${jdbc.password}</value>
        </property>
        <property name="maxActive">
            <value>${jdbc.maxActive}</value>
        </property>
        <property name="maxIdle">
            <value>${jdbc.maxIdle}</value>
        </property>
        <property name="testOnBorrow" value="true"/>
        <property name="validationQuery" value="${jdbc.getdate.sql}"/>
       
    </bean>
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager"
        proxy-target-class="true" />
    <bean id="org.springframework.jdbc.core.JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <bean id="com.domain.repository.Repository"
        class="com.repository.RepositoryJpaImpl">
        <property name="jdbcTemplate" ref="org.springframework.jdbc.core.JdbcTemplate" />
    </bean>

實體class

@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class BillContent extends AbstractPersistable implements Persistable

---------------------------------------

 

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/cuker919/archive/2010/10/26/5966862.aspx

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述