Hibernate的cache管理:
Cache就是緩存,它往往是提高系統性能的最重要手段,對數據起到一個蓄水池和緩沖的作用。Cache對於大量依賴數據讀取操作的系統而言尤其重要。在大並發量的情況下,如果每次程序都需要向數據庫直接做查詢操作,它們所帶來的性能開銷是顯而易見的,頻繁的網絡輿,數據庫磁盤的讀寫操作都會大大降低系統的性能。此時如果能讓數據庫在本地內存中保留一個鏡像,下次訪問的時候只需要從內存中直接獲取,那么顯然可以帶來不小的性能提升。引入Cache機制的難點是如何保證內存中數據的有效性,否則臟數據的出現將會給系統帶來難以預知的嚴重后果。雖然一個設計得很好的應用程序不用Cache也可以表現出讓人接受的性能,但毫無疑問,一些對讀取操作要求比較高的應用程序可以通過Cache獲得更高的性能。對於應用程序,Cache通過內存或磁盤保存了數據庫中的當前有關數據狀態,它是一個存儲在本地的數據備份。Cache位於數據庫和應用程序之間,從數據庫更新數據,並給程序提供數據。
Hibernate實現了良好的Cache機制,可以借助Hibernate內部的Cache迅速提高系統的數據讀取性能。Hibernate中的Cache可分為兩層:一級Cache和二級Cache。
一級緩存:
Hibernate默認是開啟一級緩存的,一級緩存存放在session上,屬於事務級數據緩沖。
二級緩存:
二級緩存是在SessionFactory,所有的Session共享同一個二級Cache。二級Cache的內部如何實現並不重要,重要的是采用哪種正確的緩存策略,以及采用哪個Cache提供器。
在Hibernate中使用EhCache:
1)hibernate.cfg.xml 中增加對二級緩存的配置(maven項目放在resources文件夾下)
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- Database connection settings --> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost:3306/test?characterEncoding=GBK</property> <property name="connection.username">root</property> <property name="connection.password">admin</property> <!-- SQL dialect --> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <property name="current_session_context_class">thread</property> <property name="show_sql">true</property> <property name="hbm2ddl.auto">update</property> <property name="hibernate.cache.use_second_level_cache">true</property> <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property> <mapping resource="com/how2java/pojo/Product.hbm.xml" /> <mapping resource="com/how2java/pojo/Category.hbm.xml" /> <mapping resource="com/how2java/pojo/User.hbm.xml" /> </session-factory> </hibernate-configuration>
2)ehcache.xml用戶EhCache配置(maven項目放在resources文件夾下)
<ehcache> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" /> </ehcache>
3)設置hbm
對於要進行二級緩存的實體類,進行配置,增加
1:事務(Transaction)僅在受管理的環境中可用。它保證可重讀的事務隔離級別,可以對讀/寫比例高,很少更新的數據采用該策略。
2:讀寫(read-write)使用時間戳機制維護讀寫提交事務隔離級別。可以對讀/寫比例高,很少更新的數據采用該策略。
3:非嚴格讀寫(notstrict-read-write)不保證Cache和數據庫之間的數據庫的一致性。使用此策略時,應該設置足夠的緩存過期時間,否則可能從緩存中讀出臟數據。當一些數據極少改變,並且當這些數據和數據庫有一部份不量影響不大時,可以使用此策略。
4:只讀(read-only)當確保數據永不改變時,可以使用此策略。
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.domain"> <class name="Category" table="category"> <cache usage="read-write" /><!-- 二級緩存配置 --> <id name="id" column="id"> <generator class="native"> </generator> </id> <property name="name" column="name"/> </class> </hibernate-mapping>
4)測試效果
使用不同的session,都去獲取id=1的category,只會訪問一次數據庫。因為第二次獲取雖然沒有從第二個session中拿到緩存,但是從sessionfactory中拿到了Category緩存對象。
log1 Hibernate: select category0_.id as id1_0_, category0_.name as name1_0_ from category category0_ where category0_.id=? log2 log3
//一級緩存session System.out.println("log1"); Category c1 = (Category)session.get(Category.class, 1); System.out.println("log2"); Category c2 = (Category)session.get(Category.class, 1);//不會顯示SQL語句 //提交事務 session.getTransaction().commit(); //二級緩存SessionFactory Session session2 = factory.openSession(); session2.beginTransaction(); System.out.println("log3"); Category p3 = (Category) session2.get(Category.class, 1);//不會顯示 session2.getTransaction().commit();
5)注意事項
maven所需包,hibernate 3.0版本,hibernate-ehcache
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>3.6.10.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId> <version>3.6.7.Final</version> </dependency>