您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“Hibernate中緩存機制的示例分析”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“Hibernate中緩存機制的示例分析”這篇文章吧。
具體如下。
Student.java:
public class Student { /*學生ID*/ private int id; /*學生姓名*/ private String name; /*學生和班級的關系*/ private Classes classes; //省略setter和getter方法 }
Classes.java:
public class Classes { /*班級ID*/ private int id; /*班級名稱*/ private String name; /*班級和學生的關系*/ private Set<Student> students; //省略setter和getter方法 }
Student.hbm.xml:
<?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 package="com.lixue.bean"> <class name="Student" table="t_student"> <id name="id"> <generator class="native"/> </id> <!-- 映射普通屬性 --> <property name="name"/> <!-- 多對一 映射,在多的一端加上外鍵--> <many-to-one name="classes" column="classesid"/> </class> </hibernate-mapping>
Classes.hbm.xml:
<?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 package="com.lixue.bean"> <!-- 設置lazy為false --> <class name="Classes" table="t_classes" lazy="false"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <!-- 一對多映射 ,inverse="true"表示交給對端維護關系--> <set name="students" inverse="true"> <key column="classesid"/> <one-to-many class="Student"/> </set> </class> </hibernate-mapping>
一級緩存聲明周期很短和session的生命周期一致,一級緩存也叫session級的緩存或事物級緩存,一級緩存是緩存對象的,并不能緩存屬性。
測試方法(在同一個session中使用load()查詢兩次):
/*取出來之后會放在緩存中,第二次取的時候會直接從緩存取出*/ Student student = (Student)session.load(Student.class, 1); System.out.println("student.name=" + student.getName()); /*不會發出查詢語句,load使用緩存*/ student = (Student)session.load(Student.class, 1); System.out.println("student.name=" + student.getName());
注:我們會發現,當我們第一次查詢的時候,查出來的結果是會放在session即緩存即一級緩存中的。第二次load()后及時去獲取值的時候也沒有在發出語句到數據庫中查詢了,而是直接從緩存中取值了(必須是在同一session中)。
測試方法二(在同一session中):
Student student = new Student(); student.setName("張三"); Serializable id = session.save(student); student = (Student)session.load(Student.class, id); //不會發出查詢語句,因為save支持緩存 System.out.println("student.name=" + student.getName());
注:調用了save()方法再使用load()去加載對象,然后真正獲取name屬性,但是此時并不會發出語句去查詢數據庫。因為save()方法也是支持緩存的。
測試大批量數據的添加:
public void testCache7() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); for (int i=0; i<100; i++) { Student student = new Student(); student.setName("張三" + i); session.save(student); //每20條更新一次 if (i % 20 == 0) { //清除緩存,調用flush之后數據就會保存到數據庫 session.flush(); //清除緩存的內容 session.clear(); } } session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } }
注:
1.因為save()方法支持緩存,那就存在一個問題,如果我要同時存1000萬條數據,那緩存中豈不是有1000萬的緩存對象,那就很可能導致溢出。所以說Hibernate并不能很好的支持大批量數據的更新操作,但是我們也可以很靈活的處理這個問題,比如使用循環每20條數據清除一次緩存。
2.save,update,saveOrUpdate,load,get,list,iterate,lock這些方法都會將對象放在一級緩存中,一級緩存不能控制緩存的數量,所以要注意大批量操作數據時可能造成內存溢出;可以用evict,clear方法清除緩存中的內容。
二級緩存也稱為進程級緩存或SessionFactory級緩存,二級緩存可以被所有的session緩存共享。二級緩存的生命周期和SessionFactory的生命周期一致,SessionFactory可以管理二級緩存,二級緩存的原則是當讀遠大于寫的時候使用,二級緩存也主要是緩存實體對象的。
1.將ehcahe.xml文件拷貝到src目錄下。
2.在Hibernate.cfg.xml文件中加入緩存產品提供商,如下:
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
3.啟用二級緩存(可以不顯示啟動,因為默認就是啟用的),如下:
<property name="hibernate.cache.use_second_level_cache">true</property>
4.指定哪些實體類使用二級緩存。
5.導入緩存使用的接口jar包:lib\optional\ehcache\ehcache-core-2.4.3.jar
ehcache.xml文件的內容:
<defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" />
注:
1.maxElementsInMemory表示緩存中最多存放的對象。
2.eternal表示是否永遠不過期(設置為false更有實際意義,如果為true的話表示永遠不過期,那么下面的屬性都沒什么意義了)。
3.timeToIdleSecods表示一個對象第一次被訪問后經過多長時間沒被訪問就清除。
4.timeToLiveSecods表示一個對象的存貨時間。
5.overflowToDisk為true表示緩存中超出了maxElementsInMemory指定的個數就存到磁盤中。
指定溢出時保存的磁盤路徑:
<diskStore path="java.io.tmpdir"/>
注:這個路徑可以改。
測試方法(一級緩存的前提是必須在同一個session,現在我們使用二級緩存來看看在兩個不同的session中是否存在緩存):
public void testCache1() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); Student student = (Student)session.load(Student.class, 1); System.out.println("student.name=" + student.getName()); session.getTransaction().commit(); } catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } finally { HibernateUtils.closeSession(session); } try { session = HibernateUtils.getSession(); session.beginTransaction(); Student student = (Student)session.load(Student.class, 1); //不會發出查詢語句,因為配置二級緩存,session可以共享二級緩存中的數據 //二級緩存是進程級的緩存 System.out.println("student.name=" + student.getName()); session.getTransaction().commit(); } catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } finally { HibernateUtils.closeSession(session); } }
注:如果配置了二級緩存,我們會發現,即使第一個session關閉了,再開啟另外一個session去加載數據也不會發出語句到數據庫中去查詢數據,因為配置了二級緩存,它是整個sessionFactory共享的。
禁用二級緩存實現大批量數據的添加:
public void testCache5() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); //禁止一級緩存和二級緩存交互 session.setCacheMode(CacheMode.IGNORE); for (int i=0; i<100; i++) { Student student = new Student(); student.setName("張三" + i); session.save(student); //每20條更新一次 if (i % 20 == 0) { session.flush(); //清除緩存的內容 session.clear(); } } session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); }finally { HibernateUtils.closeSession(session); } }
注:session.flush()表示清除一級緩存,但是我們又開起了二級緩存,save()之后也保存到了二級緩存,還是存在緩存過大導致溢出的情況。所以這種情況下我們應該禁用二級緩存:session.setCacheMode(CacheMode.IGNORE);
查詢緩存:一級緩存和二級緩存都是緩存實體對象的,但是有些時候我們希望獲取某些屬性的時候也不要頻繁的去訪問數據庫,而是從緩存中獲取,此時我們就可以使用查詢緩存。另外查詢緩存對實體對象的結果集會緩存ID。查詢緩存的生命周期,當關聯的表發生修改,查詢緩存的聲明周期就結束,和session的生命周期無關。
1.修改hibernate.cfg.xml文件,來開啟查詢緩存,默認是false即不開啟的,應如下設置:
<property name="hibernate.cache.use_query_cache">true</property>
2.必須在程序中啟用,如:
query.setCacheable(true)
測試方法:
public void testCache2() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); List names = session.createQuery("select s.name from Student s") .setCacheable(true) .list(); for (int i=0; i<names.size(); i++) { String name = (String)names.get(i); System.out.println(name); } session.getTransaction().commit(); } catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } finally { HibernateUtils.closeSession(session); } System.out.println("-------------------------------------------------------"); try { session = HibernateUtils.getSession(); session.beginTransaction(); //不會發出查詢語句,因為查詢緩存和session的生命周期沒有關系 List names = session.createQuery("select s.name from Student s") .setCacheable(true) .list(); for (int i=0; i<names.size(); i++) { String name = (String)names.get(i); System.out.println(name); } session.getTransaction().commit(); } catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } finally { HibernateUtils.closeSession(session); } }
注:上述代碼中,我們關閉了二級緩存,開啟了查詢緩存,然后查詢普通屬性。運行測試代碼我們可以發現,在第一個session中第一次查詢發出了一條語句,然后關閉了session,接著再第二個session中進行查詢,我們會發現第二個session中的查詢并沒有發出語句,這說明查詢緩存和session的生命周期沒有什么關系。
hibernate.cfg.xml的緩存配置:
<!-- 設置指定二級緩存的實現接口 --> <property name="hibernate.cache.region.factory_class">org.hibernate.cache.EhCacheRegionFactory</property> <!-- 設置二級緩存所使用的配置文件 --> <property name="net.sf.ehcache.configurationResourceName">/ehcache.xml</property> <!-- 設置使用QUERY查詢緩存 --> <property name="hibernate.cache.use_query_cache">true</property> <!-- 加載對象關系映射文件 --> <mapping resource="com/lixue/bean/Classes.hbm.xml" /> <mapping resource="com/lixue/bean/Student.hbm.xml" /> <!-- 必須先引入資源映射文件(就是實體映射文件)后再設置有使用二級緩存的實體類 --> <class-cache usage="read-only" class="com.lixue.bean.Student" />
以上是“Hibernate中緩存機制的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。