Hibernateキャッシュメカニズムの実例コード解析


本論文で研究したのは主にHibernateキャッシュメカニズムに関する内容であり、具体的には以下の通りである。
プレゼンテーション:
Student.java:

public class Student {
	/*  ID*/
	private int id;
	/*    */
	private String name;
	/*        */
	private Classes classes;
	//  setter getter  
}
Class.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> 
クラスes.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レベルのキャッシュまたは物事レベルのキャッシュと呼ばれています。一級キャッシュはキャッシュ対象であり、属性をキャッシュすることはできません。
テスト方法(同じセッションでロード()クエリを2回使用する):

/*           ,               */ 
      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すなわちキャッシュである一級キャッシュに置かれていることを発見します。二回目のロード()後、適時に値を取得する時も文を出してデータベースに問い合わせていません。直接にキャッシュから値を取りました。
試験方法二(同一セッション中):

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()メソッドを呼び出してからオブジェクトをロードし、本当にname属性を取得しますが、この場合は文を出してデータベースを調べません。セーブ方法もキャッシュをサポートしていますので。
大ロットデータの追加をテストします。

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()メソッドがキャッシュをサポートしているので、1つの問題があります。もし私が同時に1000万件のデータを保存したいなら、キャッシュの中に1000万のキャッシュの対象があるのではないですか?だから、Hibernateは大量のデータの更新操作をうまくサポートできません。でも、私達はこの問題を柔軟に処理できます。例えば、20個のデータを循環して一回のキャッシュをクリアします。
2.save、udate、saveOrUpdate、load、get、list、iterate、lockのこれらの方法はいずれも対象を1級のキャッシュに置いて、1級のキャッシュはキャッシュの数量を制御できないので、大量のデータを操作する時メモリがオーバーフローする可能性があります。evict、clearでキャッシュの内容をクリアできます。
レベル2キャッシュ:
二級キャッシュは、プロセスレベルキャッシュまたはSession Factoryレベルキャッシュとも呼ばれ、二級キャッシュはすべてのsessionキャッシュによって共有されることができる。セカンダリキャッシュのライフサイクルはSession Factoryのライフサイクルと一致しています。Session Factoryはセカンドキャッシュを管理できます。セカンドキャッシュの原則は読みが書きより大きいときに使います。セカンダリキャッシュも主にキャッシュエンティティオブジェクトです。
二段キャッシュの設定:
1.ehcahe.xmlファイルをsrcディレクトリにコピーします。
2.Hiberna.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.maxElements InMemoryはキャッシュに最も多く保存されているオブジェクトを表します。
2.eternalは永遠に期限が切れないかどうかを表しています。(falseに設定するとより実際的な意味があります。trueの場合は永遠に期限が切れないことを示しています。以下の属性は意味がありません。)
3.timeToIdleSecodsは、オブジェクトが初めて訪問された後、どれぐらいの時間が経っても訪問されずにクリアされると表しています。
4.timeToLiveSecodsは対象の在庫時間を表します。
5.overflowToDiskはtrueでキャッシュ中にmaxElements InMemoryで指定された個数を超えてディスクに保存されます。
オーバーフロー時に保存するディスクのパスを指定します。

<diskStore path="java.io.tmpdir"/>
このパスは変更できます。
テスト方法(一級キャッシュの前提は同じセッションである必要があります。今は二級キャッシュを使って、二つの異なるセッションにキャッシュがあるかどうかを確認します。)

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);
	}
}
注:2級のキャッシュを設定したら、最初のセッションがオフになっても、もう一つのセッションを開いてデータをロードしても文がデータベースに検索されません。2級のキャッシュが配置されていますので、session Factory全体で共有されています。
二段階キャッシュを無効にして、大量のデータの追加を実現します。

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をキャッシュする。クエリーキャッシュのライフサイクルは、関連テーブルが変更されると、クエリキャッシュの宣言周期が終了し、セッションのライフサイクルとは無関係です。
クエリーキャッシュの設定:
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のライフサイクルには関係がないということです。
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キャッシュメカニズムの実例となるコード解析のすべての内容について、ご協力をお願いします。興味のある方は引き続き当駅の他のテーマを参照してください。友達のサポートに感謝します。