緩存是關(guān)于應(yīng)用程序性能的優(yōu)化,降低了應(yīng)用程序?qū)ξ锢頂?shù)據(jù)源訪問(wèn)的頻次,從而提高應(yīng)用程序的運(yùn)行性能。
緩存對(duì) Hibernate 來(lái)說(shuō)也是重要的,它使用了如下解釋的多級(jí)緩存方案:
第一級(jí)緩存是 Session 緩存并且是一種強(qiáng)制性的緩存,所有的要求都必須通過(guò)它。Session 對(duì)象在它自己的權(quán)利之下,在將它提交給數(shù)據(jù)庫(kù)之前保存一個(gè)對(duì)象。
如果你對(duì)一個(gè)對(duì)象發(fā)出多個(gè)更新,Hibernate 會(huì)嘗試盡可能長(zhǎng)地延遲更新來(lái)減少發(fā)出的 SQL 更新語(yǔ)句的數(shù)目。如果你關(guān)閉 session,所有緩存的對(duì)象丟失,或是存留,或是在數(shù)據(jù)庫(kù)中被更新。
第二級(jí)緩存是一種可選擇的緩存并且第一級(jí)緩存在任何想要在第二級(jí)緩存中找到一個(gè)對(duì)象前將總是被詢問(wèn)。第二級(jí)緩存可以在每一個(gè)類和每一個(gè)集合的基礎(chǔ)上被安裝,并且它主要負(fù)責(zé)跨會(huì)話緩存對(duì)象。
任何第三方緩存可以和 Hibernate 一起使用。org.hibernate.cache.CacheProvider 接口被提供,它必須實(shí)現(xiàn)來(lái)給 Hibernate 提供一個(gè)緩存實(shí)現(xiàn)的解決方法。
Hibernate 也實(shí)現(xiàn)了一個(gè)和第二級(jí)緩存密切集成的查詢結(jié)果集緩存。
這是一個(gè)可選擇的特點(diǎn)并且需要兩個(gè)額外的物理緩存區(qū)域,它們保存著緩存的查詢結(jié)果和表單上一次更新時(shí)的時(shí)間戳。這僅對(duì)以同一個(gè)參數(shù)頻繁運(yùn)行的查詢來(lái)說(shuō)是有用的。
Hibernate 使用默認(rèn)的一級(jí)緩存并且你不用使用一級(jí)緩存。讓我們直接看向可選的二級(jí)緩存。不是所有的類從緩存中獲益,所以能關(guān)閉二級(jí)緩存是重要的。
Hibernate 的二級(jí)緩存通過(guò)兩步設(shè)置。第一,你必須決定好使用哪個(gè)并發(fā)策略。之后,你使用緩存提供程序來(lái)配置緩存到期時(shí)間和物理緩存屬性。
一個(gè)并發(fā)策略是一個(gè)中介,它負(fù)責(zé)保存緩存中的數(shù)據(jù)項(xiàng)和從緩存中檢索它們。如果你將使用一個(gè)二級(jí)緩存,你必須決定,對(duì)于每一個(gè)持久類和集合,使用哪一個(gè)并發(fā)策略。
如果我們將為我們的 Employee 類使用二級(jí)緩存,讓我們使用 read-write 策略來(lái)添加需要告訴 Hibernate 來(lái)緩存 Employee 實(shí)例的映射元素。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="Employee" table="EMPLOYEE">
<meta attribute="class-description">
This class contains the employee detail.
</meta>
<cache usage="read-write"/>
<id name="id" type="int" column="id">
<generator class="native"/>
</id>
<property name="firstName" column="first_name" type="string"/>
<property name="lastName" column="last_name" type="string"/>
<property name="salary" column="salary" type="int"/>
</class>
</hibernate-mapping>
usage="read-write" 參數(shù)告訴 Hibernate 為定義的緩存使用 read-write 并發(fā)策略。
在考慮你將為你的緩存候選類所使用的并發(fā)策略后你的下一步是挑選一個(gè)緩存提供者。Hibernate 讓你為整個(gè)應(yīng)用程序選擇一個(gè)單獨(dú)的緩存提供者。
S.N. | 緩存名 | 描述 |
---|---|---|
1 | EHCache | 它能在內(nèi)存或硬盤上緩存并且集群緩存,而且它支持可選的 Hibernate 查詢結(jié)果緩存。 |
2 | OSCache | 支持在一個(gè)單獨(dú)的 JVM 中緩存到內(nèi)存和硬盤,同時(shí)有豐富的過(guò)期策略和查詢緩存支持。 |
3 | warmCache | 一個(gè)基于 JGroups 的聚集緩存。它使用集群失效但是不支持 Hibernate 查詢緩存。 |
4 | JBoss Cache | 一個(gè)也基于 JGroups 多播庫(kù)的完全事務(wù)性的復(fù)制集群緩存。它支持復(fù)制或者失效,同步或異步通信,樂(lè)觀和悲觀鎖定。Hibernate 查詢緩存被支持。 |
每一個(gè)緩存提供者都不和每個(gè)并發(fā)策略兼容。以下的兼容性矩陣將幫助你選擇一個(gè)合適的組合。
策略/提供者 | Read-only | Nonstrictread-write | Read-write | Transactional |
---|---|---|---|---|
EHCache | X | X | X | |
OSCache | X | X | X | |
SwarmCache | X | X | ||
JBoss Cache | X | X |
你將在 hibernate.cfg.xml 配置文件中指定一個(gè)緩存提供者。我們選擇 EHCache 作為我們的二級(jí)緩存提供者:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
<!-- Assume students is the database name -->
<property name="hibernate.connection.url">
jdbc:mysql://localhost/test
</property>
<property name="hibernate.connection.username">
root
</property>
<property name="hibernate.connection.password">
root123
</property>
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
<!-- List of XML mapping files -->
<mapping resource="Employee.hbm.xml"/>
</session-factory>
</hibernate-configuration>
現(xiàn)在,你需要指定緩存區(qū)域的屬性。EHCache 有它自己的配置文件,ehcache.xml,它應(yīng)該在應(yīng)用程序的 CLASSPATH 中。Employee 類的 ehcache.xml 緩存配置像如下這樣:
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
<cache name="Employee"
maxElementsInMemory="500"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
/>
就是這樣,現(xiàn)在我們有 Employee 類的二級(jí)緩存并且 Hibernate 現(xiàn)在能命中緩存無(wú)論是你導(dǎo)航到 Employee 時(shí)或是當(dāng)你通過(guò)標(biāo)識(shí)符上傳 Employee 時(shí)。
你應(yīng)該為每個(gè)類分析你所有的類并選擇合適的緩存策略。有時(shí)候,二級(jí)緩存可能使應(yīng)用程序的表現(xiàn)下降。所以首先不允許緩存用基準(zhǔn)程序測(cè)試你的應(yīng)用程序,然后開(kāi)啟合適的緩存,之后檢測(cè)表現(xiàn)是推薦的。如果緩存不提升系統(tǒng)表現(xiàn)那么支持任何類型的緩存都是沒(méi)有意義的。
為了使用查詢緩存,你必須首先使用配置文件中的 hibernate.cache.use_query_cache="true" 屬性激活它。通過(guò)設(shè)置這個(gè)屬性為真,你使得 Hibernate 創(chuàng)建內(nèi)存中必要的緩存來(lái)保存查詢和標(biāo)識(shí)符集。
然后,為了使用查詢緩存,你使用 Query 類的 setCacheable(Boolean) 方法。例如:
Session session = SessionFactory.openSession();
Query query = session.createQuery("FROM EMPLOYEE");
query.setCacheable(true);
List users = query.list();
SessionFactory.closeSession();
Hibernate 通過(guò)緩存區(qū)域的概念也支持非常細(xì)粒度的緩存支持。一個(gè)緩存區(qū)域是被給予名字的緩存部分。
Session session = SessionFactory.openSession();
Query query = session.createQuery("FROM EMPLOYEE");
query.setCacheable(true);
query.setCacheRegion("employee");
List users = query.list();
SessionFactory.closeSession();
這段代碼使用方法來(lái)告訴 Hibernate 存儲(chǔ)和尋找緩存 employee 區(qū)域的查詢。
更多建議: