キャッシュ ソリューションを決して作成しないでください

データベースの操作を高速化するもう 1 つの方法は、以前にすでにリクエストしたオブジェクトをキャッシュすることです。

重要!決して独自のキャッシュ ソリューションを作成しないでください。この作業には、あなたが夢にも思わなかった落とし穴がたくさんあります。

発行 1 -キャッシュのフラッシュ。オブジェクトをキャッシュから削除する必要がある場合、またはキャッシュ内で更新する必要がある場合に、イベントが発生することがあります。これを適切に行う唯一の方法は、すべてのリクエストをキャッシュ エンジンを通じてデータベースに渡すことです。それ以外の場合は、毎回、キャッシュ内のどのオブジェクトを削除または更新するかを明示的にキャッシュに指示する必要があります。

問題 2 -メモリ不足。メモリ内のオブジェクトが多くのスペースを占有していることがわかるまでは、キャッシュは素晴らしいアイデアのように思えます。サーバー アプリケーション キャッシュが効果的に機能するには、さらに数十ギガバイトのメモリが必要です。

また、メモリ不足は常に存在するため、キャッシュからオブジェクトを削除するための効果的な戦略が必要です。これは Java のガベージ コレクターに似ています。そして、ご記憶のとおり、何十年もの間、優秀な頭脳は世代などによって物体に印を付けるさまざまな方法を発明してきました。

問題 3 -さまざまな戦略。実際に見てみると、オブジェクトごとにキャッシュに保存および更新するためのさまざまな戦略が効果的です。効率的なキャッシュ システムでは、すべてのオブジェクトに対して 1 つの戦略だけを実行することはできません。

問題 4 -の効率的な保管。オブジェクトを単にキャッシュに保存することはできません。オブジェクトには他のオブジェクトへの参照が含まれていることが多く、このままでは、ガベージ コレクターは必要なくなります。削除するものがないだけです。

したがって、オブジェクト自体を保存する代わりに、そのプリミティブ フィールドの値を保存する方がはるかに効率的な場合があります。そしてそれらに基づいてオブジェクトを迅速に構築するシステム。

その結果、仮想 DBMS 全体がメモリ内に取得され、高速に動作し、メモリの消費もほとんどなくなります。

データベースのキャッシュ

Java プログラム内で直接キャッシュすることに加えて、キャッシュはデータベース内で直接組織化されることもよくあります。

大きく分けて次の 4 つのアプローチがあります。

最初のアプローチは、データベースを非正規化することです。SQL サーバーは、テーブルにデータを保存する方法とは異なる方法でデータをメモリに保存します。

データがディスク上のテーブルに保存される場合、開発者はデータの重複をできる限り回避しようとすることがよくあります。このプロセスはデータベースの正規化と呼ばれます。したがって、メモリ内のデータの処理を高速化するために、逆のプロセス、つまりデータベースの非正規化が実行されます。関連する多数のテーブルを、巨大なテーブルなどの形式で結合した形式ですでに保存できます。

2 番目のアプローチはクエリ キャッシュです。そしてクエリ結果。

DBMS は、同じまたは類似のリクエストが頻繁に届くことを認識します。次に、これらのリクエストとその応答のキャッシュを開始します。ただし同時に、データベース内で変更された行が適時にキャッシュから削除されるようにする必要があります。

このアプローチは、クエリを分析し、DBMS がクエリをキャッシュする最適な方法を判断するのを支援できる人間にとって非常に効果的です。

3 番目のアプローチは、インメモリ データベースです。

もう 1 つの一般的に使用されるアプローチ。サーバーと DBMS の間に別のデータベースが配置され、すべてのデータがメモリ内にのみ保存されます。インメモリDBとも呼ばれます。多数の異なるサーバーが同じデータベースにアクセスしている場合、In-Memory-DB を使用すると、特定のサーバーのタイプに基づいてキャッシュを整理できます。

例:

アプローチ 4 -データベース クラスター。いくつかの読み取り専用ベース。

もう 1 つの解決策は、クラスタを使用することです。同じタイプの複数の DBMS に同一のデータが含まれています。同時に、すべてのデータベースからデータを読み取り、1 つのデータベースにのみ書き込むことができます。その後、残りのデータベースと同期されます。

これは、構成が簡単で実際に機能するため、非常に優れたソリューションです。通常、データベースに対するデータ変更リクエストが 1 件発生すると、データ読み取りリクエストが 10 ~ 100 件発生します。

Hibernate でのキャッシュの種類

Hibernate は 3 つのレベルのキャッシュをサポートしています。

  • セッションレベルでのキャッシュ(セッション)
  • SessionFactory レベルでのキャッシュ
  • リクエストのキャッシュ (およびその結果)

このシステムを次のような図の形で表現してみることができます。

最も単純なタイプのキャッシュ (第 1 レベル キャッシュとも呼ばれる) は、Hibernate セッション レベルで実装されます。Hibernate は常にデフォルトでこのキャッシュを使用し無効にすることはできません

早速次の例を考えてみましょう。

Employee director1 = session.get(Employee.class, 4);
Employee director2 = session.get(Employee.class, 4);

assertTrue(director1 == director2);

ここではデータベースに対する 2 つのクエリが実行されるように見えますが、そうではありません。データベースへの最初のリクエストの後、Employee オブジェクトがキャッシュされます。また、同じセッション内でオブジェクトを再度クエリすると、Hibernate は同じ Java オブジェクトを返します。

同じオブジェクトとは、オブジェクト参照さえも同一であることを意味します。本当に同じ物体なんですね。

save()update()saveOrUpdate()load()get()list()iterate() 、およびscroll()メソッドは、常に第 1 レベルのキャッシュを使用します。実際には、これ以上付け加えることは何もありません。

第 2 レベルのキャッシュ

第 1 レベルのキャッシュがセッション オブジェクトにバインドされている場合、第 2 レベルのキャッシュもセッション オブジェクトにバインドされます。セッションファクトリー。つまり、このキャッシュ内のオブジェクトの可視性は、一次キャッシュよりもはるかに広いということです。

例:

Session session = factory.openSession();
Employee director1 = session.get(Employee.class, 4);
session.close();

Session session = factory.openSession();
Employee director2 = session.get(Employee.class, 4);
session.close();

assertTrue(director1 != director2);
assertTrue(director1.equals(director2));

この例では、データベースに対して 2 つのクエリが実行されます。Hibernate は同一のオブジェクトを返しますが、それは同じオブジェクトではなく、異なる参照を持つことになります。

第 2 レベルのキャッシュはデフォルトでは無効になっています。したがって、データベースに対するクエリは 1 つではなく 2 つになります。

これを有効にするには、hibernate.cfg.xml ファイルに次の行を記述する必要があります。

<property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.SingletEhCacheProvider"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>

第 2 レベルのキャッシュを有効にすると、Hibernate の動作が少し変わります。

Session session = factory.openSession();
Employee director1 = session.get(Employee.class, 4);
session.close();

Session session = factory.openSession();
Employee director2 = session.get(Employee.class, 4);
session.close();

assertTrue(director1 == director2);

これらすべての操作を行った後にのみ 2 次キャッシュが有効になり、上記の例では、データベースへのクエリが 1 つだけ実行されます。