検索
ホームページJava&#&チュートリアルJava の Hibernate フレームワークにおけるキャッシュと 2 次キャッシュの詳細な説明

キャッシュ

今日は、エンティティのステータスと休止状態での休止状態キャッシュについて説明します。
1) まず、エンティティのステータスを見てみましょう:
エンティティのステータスには、主に一時的、永続的、分離の 3 つのタイプがあります。
英語で読めばおそらく理解できるはずです。
一時的: データがまだデータベース内のデータに対応していないことを意味します。
永続的: データがデータベース内のデータに対応し、変更がデータベースに反映されることを意味します。
分離: データはデータベース内のデータに対応しますが、セッションが閉じられているため、セッションによる変更はデータベース内のレコードに影響を与えないことを意味します。
コードに直接進みましょう:

Transaction tx = session.beginTransaction(); 
User user = new User(); 
user.setName("shun"); 
//这里的user还未保存到数据库,数据库表中并没有与之对应的记录,它为transient状态 
session.save(user); 
tx.commit(); 
//提交之后user变为persistent状态 
session.close(); 
//由于session关闭,此时的user为detached状态,它的所有修改都不会反映到数据库中。 
      
Session session2 = sessionFactory.openSession(); 
tx = session2.beginTransaction(); 
user.setName("shun123"); 
session2.saveOrUpdate(user); 
tx.commit(); 
//当我们调用了saveOrUpdate之后,user重新变为persistent状态,它的所有修改都会反映到数据库中。 
session2.close();

コードを見ると、まずオブジェクト ユーザーを定義します。保存される前は一時的な状態であり、データベースには対応するレコードがありません。変更を保存して送信すると、ユーザーは永続化され、データベースに対応するレコードが保持されます。セッションを閉じるとユーザーは切り離され、saveOrUpdate やその他の対応する更新および追加メソッドを手動で呼び出さない限り、その変更はデータベースに反映されません。また、永続状態から一時状態に直接変更したい場合はどうすればよいでしょうか?直接削除してください。削除後、オブジェクトはデータベース内に対応するレコードを持たなくなり、一時的な状態になります。

Hibernate の状態遷移は比較的単純です。一時状態の場合、データベースに対応するレコードはありませんが、永続化とデタッチには対応するレコードがあります。ただし、唯一の違いは、デタッチはその後にのみ存在する状態であることです。セッションは終了します。それでは、一時的なものと孤立したものの違いは何でしょうか?データベーステーブルに対応するレコードがあるかどうかという問題があります。

2) ステータスを読み込んだら、Hibernate のキャッシュを見てみましょう
Hibernate のキャッシュは、一次キャッシュと二次キャッシュの 2 種類に分かれています。
一次キャッシュ: いわゆる一次キャッシュは内部キャッシュでもあります。
第 2 レベルのキャッシュ: 休止状態では、いわゆる SessionFactory キャッシュが含まれます。これは最も安全なキャッシュ方法です。
プログラムを直接見てみましょう:

public static void main(String[] args) { 
  
  Configuration cfg = new Configuration().configure(); 
  SessionFactory sessionFactory = cfg.buildSessionFactory(); 
  Session session = sessionFactory.openSession(); 
      
  User user = (User)session.load(User.class,new Long(29)); 
  System.out.println(user.getName()); 
      
  User user2 = (User)session.load(User.class,new Long(29)); 
  System.out.println(user2.getName()); 
      
  session.close(); 
}

結果を見てみましょう:

Hibernate: select user0_.USER_ID as USER1_0_0_, user0_.USER_NAME as USER2_0_0_, user0_.age as age0_0_ from USER user0_ where user0_.USER_ID=? 
shun123123 
shun123123

この例では、load を 2 回使用しましたが、結果には SQL ステートメントが 1 つだけあり、クエリが 1 回だけ行われたことがわかります。
なぜですか?ここで Hibernate のキャッシュが役に立ちます。最初のクエリが完了すると、Hibernate は検出されたエンティティをキャッシュに置き、次回クエリを実行するときに、まずキャッシュをチェックして ID に対応するエンティティがあるかどうかを確認し、存在する場合は直接取り出します。それ以外の場合は、データベースが照会されます。

次に、コードを次のように変更します:

User user = (User)session.load(User.class,new Long(29)); 
System.out.println(user.getName()); 
      
session.evict(user);//把user从缓存中删掉 
      
User user2 = (User)session.load(User.class,new Long(29)); 
System.out.println(user2.getName()); 
      
session.close();

結果を参照してください:

Hibernate: select user0_.USER_ID as USER1_0_0_, user0_.USER_NAME as USER2_0_0_, user0_.age as age0_0_ from USER user0_ where user0_.USER_ID=?
shun123123
Hibernate: select user0_.USER_ID as USER1_0_0_, user0_.USER_NAME as USER2_0_0_, user0_.age as age0_0_ from USER user0_ where user0_.USER_ID=?
shun123123

キャッシュからユーザーを削除した後、2 番目のクエリもデータベースから直接取得されます。

2次キャッシュの話
まずエンティティクラスを見てください:

public class User implements Serializable{
  
  public Long id;
  private String name;
  private int age;
    
}

マッピングファイルは省略されており、誰でも書けるはずです。
Hibernate 設定ファイルをもう一度見てみましょう:

<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_query_cache">true</property>

Provider_class で ehcache プロバイダー クラスを指定したことがわかります。そのため、クラスパスに ehcache.xml を置く必要もあります:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
  <diskStore path="java.io.path"/>
  <defaultCache 
    maxElementsInMemory="10000"
    eternal="false"
    timeToIdleSeconds="120"
    timeToLiveSeconds="120"
    overflowToDisk="true"
    />
</ehcache>

次に、以下を見てみましょう。テストメソッドを直接実行します:

public static void main(String[] args) {
  
  Configuration cfg = new Configuration().configure();
  SessionFactory sessionFactory = cfg.buildSessionFactory();
  Session session = sessionFactory.openSession();
  
  Query query = session.createQuery("from User user where name = &#39;shun123&#39;");
  Iterator iter = query.iterate();
  while(iter.hasNext()) {
    System.out.println(((User)iter.next()).getName());
  }
    
  session.close();
    
  Session session2 = sessionFactory.openSession();
  Query query2 = session2.createQuery("from User user where name=&#39;shun123&#39;");
  Iterator iter2 = query2.iterate();
  while(iter2.hasNext()) {
    System.out.println(((User)iter2.next()).getName());
  }
    
  session2.close();
  
}


実行後、次のことがわかります:

Hibernate: select user0_.USER_ID as col_0_0_ from USER user0_ where user0_.USER_NAME=&#39;shun123&#39;
Hibernate: select user0_.USER_ID as USER1_0_0_, user0_.USER_NAME as USER2_0_0_, user0_.age as age0_0_ from USER user0_ where user0_.USER_ID=?
shun123
Hibernate: select user0_.USER_ID as col_0_0_ from USER user0_ where user0_.USER_NAME=&#39;shun123&#39;
shun123

検索のみが実行され、2 番目のクエリ中に検索用の ID が取得されないことがわかります。二次キャッシュ。

まず、テストメソッドのコードを分析しましょう。テスト メソッドでは、2 つのセッションを開き、同じクエリを実行する 2 つのクエリを作成しました。ただし、2 つのセッションはキャッシュ (2 次キャッシュと SessionFactory レベルのキャッシュ) を共有できます。セッションが同じ SessionFactory によって作成されている限り、2 次キャッシュを共有してデータベースとの対話を減らすことができます。
設定ファイルの意味を見てみましょう:

<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_query_cache">true</property>

2 次キャッシュを使用する必要がある場合は、まず 2 次キャッシュ用のアカウントを開くように

<property name="hibernate.cache.use_second_level_cache">true</property>

を設定する必要があります。 :

<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

は、2次キャッシュのプロバイダークラスを指定します。この場合、私たちは皆ehcacheを使用しますが、他のものは今のところ使用したことがなく、あまり詳しくありません。今はそれらについては話しません。
先ほどの例と同様に、上記の 2 つを設定するだけで、正常に実行され、2 次キャッシュを使用できます。
では、3 番目の文は何のためにあるのでしょうか?

<property name="hibernate.cache.use_query_cache">true</property>

この設定は、クエリ時にキャッシュを使用する必要があることを示しています。これを使用する必要がある場合は、事前に query.setCacheable(true) メソッドを呼び出して有効にする必要があります。

一緒にコードを見てみましょう (最初にキャッシュを有効にしません):

public static void main(String[] args) {
  
  Configuration cfg = new Configuration().configure();
  SessionFactory sessionFactory = cfg.buildSessionFactory();
  Session session = sessionFactory.openSession();
  
  Query query = session.createQuery("from User user where name = &#39;shun123&#39;");
  List list = query.list();
  for (int i = 0; i < list.size(); i++){
    System.out.println(((User)list.get(i)).getName());
  }
    
  session.close();
    
  Session session2 = sessionFactory.openSession();
  Query query2 = session2.createQuery("from User user where name=&#39;shun123&#39;");
  List list2 = query2.list();
  for (int i = 0; i < list2.size(); i++){
    System.out.println(((User)list.get(i)).getName());
  }
    
  session2.close();
  
}

ここでの出力結果は次のとおりです:

Hibernate: select user0_.USER_ID as USER1_0_, user0_.USER_NAME as USER2_0_, user0_.age as age0_ from USER user0_ where user0_.USER_NAME=&#39;shun123&#39;
shun123
Hibernate: select user0_.USER_ID as USER1_0_, user0_.USER_NAME as USER2_0_, user0_.age as age0_ from USER user0_ where user0_.USER_NAME=&#39;shun123&#39;
shun123

ここではリストを使用しているため、キャッシュが使用されていないことがわかります。リストはキャッシュ専用 書き込み読み取り不可。したがって、ここには 2 つのクエリがあります。
次に、それを変更しましょう:

public static void main(String[] args) {
  
  Configuration cfg = new Configuration().configure();
  SessionFactory sessionFactory = cfg.buildSessionFactory();
  Session session = sessionFactory.openSession();
  
  Query query = session.createQuery("from User user where name = &#39;shun123&#39;");
  <span style="background-color: #ffffff;"><span style="color: #ff0000;">query.setCacheable(true);</span></span>
  List list = query.list();
  for (int i = 0; i < list.size(); i++){
    System.out.println(((User)list.get(i)).getName());
  }
    
  session.close();
    
  Session session2 = sessionFactory.openSession();
  Query query2 = session2.createQuery("from User user where name=&#39;shun123&#39;");
  <span style="color: #ff0000;">query2.setCacheable(true);</span>
  List list2 = query2.list();
  for (int i = 0; i < list2.size(); i++){
    System.out.println(((User)list.get(i)).getName());
  }
    
  session2.close();
  
}

  看到红色的两句代码,这是我们进行添加的两个开启查询缓存的代码,现在我们看到结果:

Hibernate: select user0_.USER_ID as USER1_0_, user0_.USER_NAME as USER2_0_, user0_.age as age0_ from USER user0_ where user0_.USER_NAME=&#39;shun123&#39;
shun123
shun123

  只剩一次查询了,为什么呢?就在那两句红色代码处,我们开启了缓存,记住,需要使用两次。把两个query都设成可缓存的才能使用查询缓存。
 Criteria也是类似的做法,为免有些童鞋忘记了Criteria怎么写了,我还是放一下代码:

public static void main(String[] args) {
  
  Configuration cfg = new Configuration().configure();
  SessionFactory sessionFactory = cfg.buildSessionFactory();
  Session session = sessionFactory.openSession();
  
  Criteria criteria1 = session.createCriteria(User.class);
  criteria1.setCacheable(true);
  criteria1.add(Restrictions.eq("name","shun123"));
  List list = criteria1.list();
  for (int i = 0; i < list.size(); i++){
    System.out.println(((User)list.get(i)).getName());
  }
    
  session.close();
    
  Session session2 = sessionFactory.openSession();
  Criteria criteria2 = session2.createCriteria(User.class);
  criteria2.setCacheable(true);
  criteria2.add(Restrictions.eq("name","shun123"));
  List list2 = criteria2.list();
  for (int i = 0; i < list2.size(); i++){
    System.out.println(((User)list.get(i)).getName());
  }
    
  session2.close();
  
}

  我们看结果:

Hibernate: select this_.USER_ID as USER1_0_0_, this_.USER_NAME as USER2_0_0_, this_.age as age0_0_ from USER this_ where this_.USER_NAME=?
shun123
shun123

更多详解Java的Hibernate框架中的缓存与二级缓存相关文章请关注PHP中文网!

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
Java開発のどの側面がプラットフォームに依存していますか?Java開発のどの側面がプラットフォームに依存していますか?Apr 26, 2025 am 12:19 AM

javadevelopmentisnotentirelylylypratform-IndopentDuetoseveralfactors.1)jvmvariationsaffectperformanceandbehavioracrossdifferentos.2)nativeLibrariesviajniintroducePlatform-specificissues.3)giaiasystemsdifferbeTioneplateplatifflics.4)

さまざまなプラットフォームでJavaコードを実行するときにパフォーマンスの違いはありますか?なぜ?さまざまなプラットフォームでJavaコードを実行するときにパフォーマンスの違いはありますか?なぜ?Apr 26, 2025 am 12:15 AM

Javaコードは、さまざまなプラットフォームで実行するときにパフォーマンスの違いがあります。 1)JVMの実装と最適化戦略は、OracleJDKやOpenJDKなどとは異なります。 2)メモリ管理やスレッドスケジューリングなどのオペレーティングシステムの特性もパフォーマンスに影響します。 3)適切なJVMを選択し、JVMパラメーターとコード最適化を調整することにより、パフォーマンスを改善できます。

Javaのプラットフォームの独立性の制限は何ですか?Javaのプラットフォームの独立性の制限は何ですか?Apr 26, 2025 am 12:10 AM

java'splatformindepentedencehaslimitationsincludingporformanceoverhead、versioncompatibulisisues、changleSwithnativeLibraryIntegration、プラットフォーム固有の機能、およびjvminStallation/maintenation。

プラットフォームの独立性とクロスプラットフォーム開発の違いを説明します。プラットフォームの独立性とクロスプラットフォーム開発の違いを説明します。Apr 26, 2025 am 12:08 AM

PlatformEndependEncealLowsProgramStorunonAnyPlatformWithOdification、whilecross-platformdevelopmentReadreessomeplatform-specificAdjustments.platformindependence、explifiedByjava、unableSiversAlexecutionButMayCompromperformance

ジャストインタイム(JIT)コンピレーションは、Javaのパフォーマンスとプラットフォームの独立性にどのような影響を与えますか?ジャストインタイム(JIT)コンピレーションは、Javaのパフォーマンスとプラットフォームの独立性にどのような影響を与えますか?Apr 26, 2025 am 12:02 AM

jitcompalilationinjavaenhancesperformance whelemaintaining formindepence.1)itdynamicallyTrantesiNTODENATIVEMACHINECODEATRUNTIME、最適化されたコードを最適化すること、

Javaがクロスプラットフォームデスクトップアプリケーションを開発するための人気のある選択肢なのはなぜですか?Javaがクロスプラットフォームデスクトップアプリケーションを開発するための人気のある選択肢なのはなぜですか?Apr 25, 2025 am 12:23 AM

javaispopularforsoss-platformdesktopapplicationsduetoits "writeonce、runaynay" philosophy.1)itusesbytecodatiTatrunnanyjvm-adipplatform.2)ライブラリリケンディンガンドジャヴァフククレアティック - ルルクリス

Javaでプラットフォーム固有のコードを作成する必要がある場合がある状況について話し合います。Javaでプラットフォーム固有のコードを作成する必要がある場合がある状況について話し合います。Apr 25, 2025 am 12:22 AM

Javaでプラットフォーム固有のコードを作成する理由には、特定のオペレーティングシステム機能へのアクセス、特定のハードウェアとの対話、パフォーマンスの最適化が含まれます。 1)JNAまたはJNIを使​​用して、Windowsレジストリにアクセスします。 2)JNIを介してLinux固有のハードウェアドライバーと対話します。 3)金属を使用して、JNIを介してMacOSのゲームパフォーマンスを最適化します。それにもかかわらず、プラットフォーム固有のコードを書くことは、コードの移植性に影響を与え、複雑さを高め、パフォーマンスのオーバーヘッドとセキュリティのリスクをもたらす可能性があります。

プラットフォームの独立性に関連するJava開発の将来の傾向は何ですか?プラットフォームの独立性に関連するJava開発の将来の傾向は何ですか?Apr 25, 2025 am 12:12 AM

Javaは、クラウドネイティブアプリケーション、マルチプラットフォームの展開、および言語間の相互運用性を通じて、プラットフォームの独立性をさらに強化します。 1)クラウドネイティブアプリケーションは、GraalvmとQuarkusを使用してスタートアップ速度を向上させます。 2)Javaは、埋め込みデバイス、モバイルデバイス、量子コンピューターに拡張されます。 3)Graalvmを通じて、JavaはPythonやJavaScriptなどの言語とシームレスに統合して、言語間の相互運用性を高めます。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

PhpStorm Mac バージョン

PhpStorm Mac バージョン

最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

VSCode Windows 64 ビットのダウンロード

VSCode Windows 64 ビットのダウンロード

Microsoft によって発売された無料で強力な IDE エディター