Hibernate提供了兩個緩存級別:
- 一級緩存是會話緩存。 對象被緩存在當前會話中,并且它們僅在會話關閉之前是活動的。
- 只要會話工廠處于活動狀態,第二級緩存就存在。 請記住,在Hibernate情況下,二級緩存不是對象樹。 對象實例不被緩存,而是存儲屬性值。
在簡要介紹了一下Hibernate緩存之后(讓我知道這很簡短),讓我們看一下什么是查詢緩存以及如何與二級緩存相關聯。
查詢緩存負責將作為參數提供的查詢和值的組合作為鍵進行緩存,并將查詢執行返回的對象的標識符列表作為值進行緩存。 注意,使用查詢緩存也需要二級緩存,因為從緩存(即標識符列表)獲取查詢結果時, Hibernate將使用二級緩存的標識符加載對象。
概括起來,作為一個概念性的模式,給出下一個查詢:“ from country from country>:number “,第一次執行后, Hibernate緩存將包含下一個虛構值(請注意,number參數設置為1000):
L2快取
[
id:1,{name ='Spain',人口= 1000,...。} id:2,{name ='德國',人口= 2000,...} …。 QueryCache [{來自人口>:number的國家/地區,1000},{id:2}]
因此,在開始使用查詢緩存之前,我們需要配置第二級緩存。
首先,您必須確定要使用的緩存提供程序。 對于此示例,選擇了Ehcache ,但請參閱Hibernate文檔以獲取所有支持的提供程序的完整列表。
要配置二級緩存,請設置下一個休眠屬性:
hibernate.cache.provider_class = org.hibernate.cache.EhCacheProvider
hibernate.cache.use_structured_entries = true
hibernate.cache.use_second_level_cache = true
如果您使用注釋方法,請使用以下方法注釋可緩存的實體:
@可緩存
@Cache(用法= CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
可以看到在這種情況下,緩存并發策略是NONSTRICT_READ_WRITE ,但是根據緩存提供者的不同,可以遵循其他策略,例如TRANSACTIONAL,READ_ONLY ………請查看Hibernate文檔的緩存部分,以選擇最適合您需求的策略。
最后添加Ehcache依賴項:
<依賴性>
<groupId> net.sf.ehcache </ groupId>
<artifactId> ehcache-core </ artifactId> <version> 2.5.0 </ version> </ dependency> <依賴性> <groupId> org.hibernate </ groupId> <artifactId> hibernate-ehcache </ artifactId> <version> 3.6.0.Final </ version> </ dependency>
現在已配置了二級緩存,但未配置查詢緩存 ; 無論如何,我們離目標不遠。
將hibernate.cache.use_query_cache屬性設置為true 。
對于每個可緩存的查詢,我們必須在查詢創建期間調用setCachable方法:
List <Country> list = session.createQuery(“來自人口> 1000的國家/地區”).setCacheable(true).list();
為了使示例更實用,我已經使用Spring Framework上傳了完整的查詢緩存示例。 為了清楚地了解查詢緩存的工作原理,我使用了一個在ensembl.org中托管的公共數據庫。 Ensembl項目為脊椎動物和其他真核生物建立了基因組數據庫,并在線免費提供此信息。 在此示例中,對dna表的查詢被緩存。
首先進行Hibernate配置:
@Configuration
public class HibernateConfiguration {@Value("#{dataSource}")private DataSource dataSource;@Beanpublic AnnotationSessionFactoryBean sessionFactoryBean() {Properties props = new Properties();props.put("hibernate.dialect", EnhancedMySQL5HibernateDialect.class.getName());props.put("hibernate.format_sql", "true");props.put("hibernate.show_sql", "true");props.put("hibernate.cache.provider_class", "org.hibernate.cache.EhCacheProvider");props.put("hibernate.cache.use_structured_entries", "true");props.put("hibernate.cache.use_query_cache", "true");props.put("hibernate.cache.use_second_level_cache", "true");props.put("hibernate.hbm2ddl.auto", "validate");AnnotationSessionFactoryBean bean = new AnnotationSessionFactoryBean();bean.setAnnotatedClasses(new Class[]{Dna.class}); bean.setHibernateProperties(props);bean.setDataSource(this.dataSource);bean.setSchemaUpdate(true);return bean;}}
這是一個簡單的Hibernate配置,使用前面說明的屬性來配置二級緩存。
實體類是代表DNA序列的實體。
@Entity(name="dna")
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Dna {@Idprivate int seq_region_id;private String sequence;public int getSeq_region_id() {return seq_region_id;}public void setSeq_region_id(int seq_region_id) {this.seq_region_id = seq_region_id;}@Columnpublic String getSequence() {return sequence;}public void setSequence(String sequence) {this.sequence = sequence;}}
為了嘗試查詢緩存 ,我們將實現一項測試,其中多次執行同一查詢。
@Autowired
private SessionFactory sessionFactory;@Test
public void fiftyFirstDnaSequenceShouldBeReturnedAndCached() throws Exception {for (int i = 0; i < 5; i++) {Session session = sessionFactory.openSession();session.beginTransaction();Time elapsedTime = new Time("findDna"+i);List<Dna> list = session.createQuery("from dna").setFirstResult(0).setMaxResults(50).setCacheable(true).list();session.getTransaction().commit();session.close();elapsedTime.miliseconds(System.out);for (Dna dna : list) {System.out.println(dna);}}
}
我們可以看到我們正在返回前五十個dna序列,如果執行它,您將看到打印了從查詢創建到提交事務之間的經過時間。 如您所料,僅第一次迭代就需要大約5秒鐘來獲取所有數據,而其他迭代只需數毫秒。
查詢迭代之前的foreach行將通過控制臺打印對象標識符。 如果仔細觀察,這些標識符將不會在所有執行期間重復。 這個事實只是向您顯示Hibernate緩存不會保存對象而是保存屬性值,并且每次都會創建對象本身。
最后一點,請記住,默認情況下, Hibernate不緩存關聯。
現在,在編寫查詢之后,考慮它是否將包含靜態數據以及是否將經常執行。 在這種情況下, 查詢緩存是您的朋友,可以使Hibernate應用程序運行得更快。
下載代碼
參考:來自JCG合作伙伴的 Hibernate緩存級別教程 ? 在一個罐子統治他們所有博客的亞歷克斯·索托。
翻譯自: https://www.javacodegeeks.com/2012/02/hibernate-cache-levels-tutorial.html