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

Java の Hibernate フレームワークにおけるキャッシュと 2 次キャッシュの詳細な説明

Jan 23, 2017 am 09:57 AM

キャッシュ

今日は、エンティティのステータスと休止状態での休止状態キャッシュについて説明します。
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 までご連絡ください。

ホット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衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

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

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

2025年のトップ4 JavaScriptフレームワーク:React、Angular、Vue、Svelte 2025年のトップ4 JavaScriptフレームワーク:React、Angular、Vue、Svelte Mar 07, 2025 pm 06:09 PM

この記事では、2025年の上位4つのJavaScriptフレームワーク(React、Angular、Vue、Svelte)を分析し、パフォーマンス、スケーラビリティ、将来の見通しを比較します。 強力なコミュニティと生態系のためにすべてが支配的なままですが、彼らの相対的なポップ

カフェインやグアバキャッシュなどのライブラリを使用して、Javaアプリケーションにマルチレベルキャッシュを実装するにはどうすればよいですか? カフェインやグアバキャッシュなどのライブラリを使用して、Javaアプリケーションにマルチレベルキャッシュを実装するにはどうすればよいですか? Mar 17, 2025 pm 05:44 PM

この記事では、カフェインとグアバキャッシュを使用してJavaでマルチレベルキャッシュを実装してアプリケーションのパフォーマンスを向上させています。セットアップ、統合、パフォーマンスの利点をカバーし、構成と立ち退きポリシー管理Best Pra

node.js 20:キーパフォーマンスが向上し、新機能 node.js 20:キーパフォーマンスが向上し、新機能 Mar 07, 2025 pm 06:12 PM

node.js 20は、V8エンジンの改善、特により速いガベージコレクションとI/Oを介してパフォーマンスを大幅に向上させます。 新機能には、より良いWebセンブリのサポートと洗練されたデバッグツール、開発者の生産性とアプリケーション速度の向上が含まれます。

Javaのクラスロードメカニズムは、さまざまなクラスローダーやその委任モデルを含むどのように機能しますか? Javaのクラスロードメカニズムは、さまざまなクラスローダーやその委任モデルを含むどのように機能しますか? Mar 17, 2025 pm 05:35 PM

Javaのクラスロードには、ブートストラップ、拡張機能、およびアプリケーションクラスローダーを備えた階層システムを使用して、クラスの読み込み、リンク、および初期化が含まれます。親の委任モデルは、コアクラスが最初にロードされ、カスタムクラスのLOAに影響を与えることを保証します

Spring Boot Snakeyaml 2.0 CVE-2022-1471問題修正 Spring Boot Snakeyaml 2.0 CVE-2022-1471問題修正 Mar 07, 2025 pm 05:52 PM

この記事では、リモートコードの実行を可能にする重大な欠陥であるSnakeyamlのCVE-2022-1471の脆弱性について説明します。 Snakeyaml 1.33以降のSpring Bootアプリケーションをアップグレードする方法は、このリスクを軽減する方法を詳述し、その依存関係のアップデートを強調しています

Iceberg:データレイクテーブルの未来 Iceberg:データレイクテーブルの未来 Mar 07, 2025 pm 06:31 PM

大規模な分析データセットのオープンテーブル形式であるIcebergは、データの湖のパフォーマンスとスケーラビリティを向上させます。 内部メタデータ管理を通じて、寄木細工/ORCの制限に対処し、効率的なスキーマの進化、タイムトラベル、同時wを可能にします

Javaで機能的なプログラミング技術を実装するにはどうすればよいですか? Javaで機能的なプログラミング技術を実装するにはどうすればよいですか? Mar 11, 2025 pm 05:51 PM

この記事では、Lambda式、Streams API、メソッド参照、およびオプションを使用して、機能プログラミングをJavaに統合することを調べます。 それは、簡潔さと不変性を通じてコードの読みやすさと保守性の改善などの利点を強調しています

キュウリのステップ間でデータを共有する方法 キュウリのステップ間でデータを共有する方法 Mar 07, 2025 pm 05:55 PM

この記事では、キュウリの手順間でデータを共有する方法、シナリオコンテキスト、グローバル変数、引数の合格、およびデータ構造を比較する方法を調べます。 簡潔なコンテキストの使用、記述など、保守性のためのベストプラクティスを強調しています

See all articles