20 基本的なキャッシュ操作の実行
この章の内容は次のとおりです。
- NamedCache APIの概要
com.tangosol.net.NamedCache<K, V>インタフェースは、アプリケーションがキャッシュ・インスタンスを取得して、それとやりとりするために使用する主要インタフェースです。 - キャッシュ・インスタンスの取得
NamedCacheインスタンスへの参照を取得するために、アプリケーションはSessionAPIおよびCacheFactoryAPIを使用できます。 - キャッシュput操作の実行
基本的なキャッシュput操作は、Mapインタフェースで定義されているputメソッドを使用して実行されます。 - キャッシュget操作の実行
基本的なキャッシュget操作は、Mapインタフェースで定義されているgetメソッドを使用して実行されます。 - キャッシュ削除操作の実行
基本的なキャッシュ削除操作は、Mapインタフェースで定義されているremoveメソッドを使用して実行されます。 - デフォルトのマップ操作の使用
Coherenceでは、多くのMapメソッドの実装をオーバーライドして、これらの操作が分散環境で適切に実行されることを保証します。 - キャッシュの事前ロード
キャッシュの事前ロードは、アプリケーションでデータを使用する前にキャッシュに移入する場合に使用される一般的なシナリオです。 - キャッシュのクリア
キャッシュの内容は、NamedCacheインタフェースで定義されるclearまたはtruncateメソッドを使用してクリアできます。 - キャッシュの解放
キャッシュが不要になったアプリケーションでは、CacheFactory.releaseメソッドを使用して、指定されたキャッシュのインスタンスに関連付けられているローカル・リソースを解放する必要があります。 - キャッシュの破棄
CacheFactoryクラスを使用して作成されるキャッシュは、CacheFactory.destroyメソッドを使用して破棄できます。 - セッションのクローズ
セッションが不要になった場合、アプリケーションはそのセッションをクローズする必要があります。 - NameCache操作の非同期実行
com.tangosol.net.AsyncNameCache<K, V>インタフェースにより、キャッシュ操作を並列に完了できます。 - NameCache型チェックの使用
Coherenceでは、明示的な型を使用してSessionまたはCacheFactoryAPIのいずれかを使用している場合、厳密に型指定されたNamedCacheインスタンスをリクエストできます。
親トピック: データ・グリッド操作の実行
NamedCache APIの概要
com.tangosol.net.NamedCache<K, V>インタフェースは、アプリケーションがキャッシュ・インスタンスを取得して、それとやりとりするために使用する主要インタフェースです。NamedCache<K, V>インタフェースは、他のインタフェースを拡張します。これらのインタフェースはそれぞれ、Coherenceに固有で、データ・グリッド操作の実行に使用される追加のキャッシュ機能を提供します。
拡張されたインタフェースには、次のものがあります。
-
java.util.Map<K, V>- このインタフェースでは、get()、put()、remove()などの基本的なMapメソッドが提供されます。 -
com.tangosol.net.cache.CacheMap<K, V>- このインタフェースでは、キャッシュ内にあるキーの集合を取得(Mapとして)する、およびオブジェクトをキャッシュに入れるためのメソッドが提供されます。このインタフェースでは、エントリをキャッシュに入れるときに有効期限の値を追加することもできます。 -
com.tangosol.util.QueryMap<K, V>- このインタフェースでは、キャッシュを問い合せるためのメソッドが提供されます。キャッシュ内のデータの問合せを参照してください。 -
com.tangosol.util.InvocableMap<K, V>- このインタフェースでは、キャッシュ・データのサーバー側処理のためのメソッドが提供されます。キャッシュ内のデータの処理を参照してください。 -
com.tangosol.util.ObservableMap<K, V>- このインタフェースでは、キャッシュ・イベントをリスニングするためのメソッドが提供されます。(マップ・イベントの使用を参照してください)。 -
com.tangosol.util.ConcurrentMap<K, V>- このインタフェースでは、lock()やunlock()などの同時アクセスのためのメソッドが提供されます。トランザクションの実行を参照してください。
親トピック: 基本的なキャッシュ操作の実行の実行
キャッシュ・インスタンスの取得
NamedCacheインスタンスへの参照を取得するために、アプリケーションではSession APIとCacheFactory APIを使用できます。Session APIでは、非静的なCoherenceセッションの使用および注入を可能にする簡潔なメソッド・セットが提供され、これはキャッシュの取得に推奨される方法です。対照的に、CacheFactory APIでは、Coherenceの内部的な概念やサービスの知識を必要とする、多くの静的メソッドが公開されています。Session APIにより、より効率的なライフサイクルおよび他のフレームワーク、特に注入を使用するフレームワークとの統合が可能になります。
次の例では、デフォルトのセッション・プロバイダを使用してセッションを作成してから、Session.getCacheメソッドを使用してNamedCacheインスタンスへの参照を取得します。キャッシュの名前はパラメータとして含まれます。
import com.tangosol.net.*;
...
Session session = Session.create();
NamedCache<Object, Object> cache = session.getCache("MyCache");
CoherenceSessionクラスはSessionインタフェースを実装し、アプリケーションがnew演算子を使用できるようにします。たとえば:
import com.tangosol.net.*;
...
Session session = new CoherenceSession();
NamedCache<Object, Object> cache = session.getCache("MyCache");
次の例では、CacheFactory.getCacheメソッドを使用してNamedCacheインスタンスへの参照を取得し、キャッシュの名前をパラメータとして含めます。
import com.tangosol.net.*;
...
NamedCache<Object, Object> cache = CacheFactory.getCache("MyCache");
Session APIとCacheFactory APIの両方は、必要に応じて基礎となるキャッシュ・サービスを開始します。キャッシュ・インスタンスは、キャッシュ構成ファイル(デフォルトでcoherence-cache-config.xml)に定義されているキャッシュ・スキームを使用して作成されます。キャッシュ・スキームは、名前MyCacheにマップされます。キャッシュの構成を参照してください。
NamedCacheインスタンスでは、任意のタイプのキーと値を格納できます。ただし、キャッシュ・エントリを操作する場合は、型の安全性をアプリケーションで確保する必要があります。アプリケーションでは、特定の型のNamedCacheインスタンスを作成でき、APIレベルの型チェックも提供されます。NameCache型チェックの使用を参照してください。
キャッシュされたオブジェクトの要件
キャッシュのキーおよび値はシリアライズ可能である必要があります(たとえば、java.io.SerializableまたはCoherence Portable Object Formatのシリアライズ)。さらに、キャッシュ・キーはhashCode()とequals()メソッドの実装を提供する必要があり、これらのメソッドはクラスタ・ノード間で一貫性のある結果を返す必要があります。これは、hashCode()およびequals()の実装は、オブジェクトのシリアライズ可能な状態(つまり、オブジェクトの一時的でないフィールド)にのみ基づいている必要があることを示しています。String、Integer、Dateなどのほとんどの組込みのJava型はこの要件を満たしています。一部のキャッシュの実装(特にパーティション・キャッシュ)では、等価の検証にキー・オブジェクトのシリアライズされた形式を使用し、equals()でtrueを返すキーは、同様の方法でシリアライズされる必要があり、ほとんどの組込みのJava型はこの要件を満たしています。Portable Object Formatの使用を参照してください
親トピック: 基本的なキャッシュ操作の実行の実行
キャッシュput操作の実行
Mapインタフェースで定義されているputメソッドを使用して実行されます。putメソッドは、キャッシュにエントリを追加し、指定されたキーの前の値を返します。たとえば:
String key = "k1";
String value = "Hello World!";
NamedCache<Object, Object> cache = CacheFactory.getCache("MyCache");
cache.put(key, value);
putAllメソッドは、単一のバルク・ロード操作で複数のエントリをキャッシュに追加する場合に使用され、エントリはMap型のデータ構造内にある必要があります。キャッシュの事前ロードを参照してください。
親トピック: 基本的なキャッシュ操作の実行の実行
キャッシュget操作の実行
Mapインタフェースで定義されているgetメソッドを使用して実行されます。指定されたキーに対して、マップされた値が返されます。たとえば:
String key = "k1";
String value = "Hello World!";
NamedCache<Object, Object> cache = CacheFactory.getCache("MyCache");
cache.put(key, value);
System.out.println(cache.get(key));
親トピック: 基本的なキャッシュ操作の実行の実行
キャッシュ削除操作の実行
Mapインタフェースで定義されているremoveメソッドを使用して実行されます。指定されたキーのマッピングがキャッシュから削除され、前の値が戻されます。たとえば:
String key = "k1";
String value = "Hello World!";
NamedCache<Object, Object> cache = CacheFactory.getCache("MyCache");
cache.put(key, value);
System.out.println(cache.get(key));
cache.remove(key);
親トピック: 基本的なキャッシュ操作の実行の実行
デフォルトのマップ操作の使用
java.util.Mapインタフェースには、putIfAbsent、replaceAll、mergeなどの操作を実行するためのデフォルトのメソッドが含まれています。Coherenceでは、多くのMapメソッドの実装をオーバーライドして、これらの操作が分散環境で適切に実行されることを保証します。メソッドはエントリ・プロセッサを使用するために再実装されているため、ラムダ式を利用できます。メソッドは、NamedCacheインタフェースを使用する場合に使用できます。たとえば:
String key = "k1";
String value = "Hello World!";
NamedCache<Object, Object> cache = CacheFactory.getCache("hello-example");
cache.putIfAbsent(key, value);
System.out.println(cache.get(key));
ラムダ式は、必要な処理をエントリで実行する場合にも使用できます。たとえば、
cache.replaceAll((key, value) ->
{
value.setLastName(value.getLastName().toUpperCase());
return value;
});
親トピック: 基本的なキャッシュ操作の実行の実行
キャッシュの事前ロード
この項には次のトピックが含まれます:
キャッシュへのデータのバルク・ロード
putメソッドを使用して、キャッシュにデータをバルク・ロードできます。ただし、特にパーティション・キャッシュおよびレプリケート・キャッシュでは、putをコールするたびにネットワーク・トラフィックが発生する場合があります。また、putをコールするたびにキャッシュで置換されたばかりのオブジェクトが返され(java.util.Mapインタフェースで定義されている)、不要なオーバーヘッドが追加されます。
public static void bulkLoad(NamedCache cache, Connection conn)
{
Statement s;
ResultSet rs;
try
{
s = conn.createStatement();
rs = s.executeQuery("select key, value from table");
while (rs.next())
{
Integer key = new Integer(rs.getInt(1));
String value = rs.getString(2);
cache.put(key, value);
}
...
}
catch (SQLException e)
{...}
}
かわりに、ConcurrentMap.putAllメソッドを使用すると、キャッシュのロードを大幅に効率化できます。たとえば:
public static void bulkLoad(NamedCache cache, Connection conn)
{
Statement s;
ResultSet rs;
Map buffer = new HashMap();
try
{
int count = 0;
s = conn.createStatement();
rs = s.executeQuery("select key, value from table");
while (rs.next())
{
Integer key = new Integer(rs.getInt(1));
String value = rs.getString(2);
buffer.put(key, value);
// this loads 1000 items at a time into the cache
if ((count++ % 1000) == 0)
{
cache.putAll(buffer);
buffer.clear();
}
}
if (!buffer.isEmpty())
{
cache.putAll(buffer);
}
...
}
catch (SQLException e)
{...}
}
親トピック: キャッシュの事前ロード
分散バルク・ロードの実行
Coherenceのパーティション・キャッシュに大量のデータ・セットを事前移入する際は、Coherenceのクラスタ・メンバーに作業を分散すると効率が向上する可能性があります。分散ロードを使用すると、クラスタのネットワーク帯域幅およびCPU処理能力の集積を活用することによって、データ・スループット率を高めることができます。分散ロードの実行時には、アプリケーションで次の事項を決定する必要があります。
-
ロードを実行するクラスタのメンバー
-
メンバー間でのデータ・セットの分割方法
メンバーの選択および作業の分割時は、基礎となるデータ・ソース(データベースやファイル・システムなど)に対する負荷をアプリケーションで考慮する必要があります。たとえば、問合せを同時に実行するメンバーが多すぎると、1つのデータベースでは対応しきれなくなる場合があります。
親トピック: キャッシュの事前ロード
分散バルク・ロードの例
この項では、簡単な分散ロードを実行する一般的なステップの概要について説明します。この例では、データがファイルに保存されていて、クラスタ内で記憶域が有効なすべてのメンバーに分散されることを前提としています。
-
記憶域が有効なメンバーのセットを取得します。たとえば、次の方法では
getStorageEnabledMembersメソッドを使用して、分散キャッシュ内で記憶域が有効なメンバーを取得します。protected Set getStorageMembers(NamedCache cache) { return ((PartitionedService) cache.getCacheService()) .getOwnershipEnabledMembers(); } -
記憶域が有効なクラスタのメンバー間で作業を分割します。たとえば、次のルーチンでは、メンバーに割り当てられたファイルの一覧が含まれるマップが、メンバーをキーとして返されます。
protected Map<Member, List<String>> divideWork(Set members, List<String> fileNames) { Iterator i = members.iterator(); Map<Member, List<String>> mapWork = new HashMap(members.size()); for (String sFileName : fileNames) { Member member = (Member) i.next(); List<String> memberFileNames = mapWork.get(member); if (memberFileNames == null) { memberFileNames = new ArrayList(); mapWork.put(member, memberFileNames); } memberFileNames.add(sFileName); // recycle through the members if (!i.hasNext()) { i = members.iterator(); } } return mapWork; } -
各メンバーへのロードを実行するタスクを起動します。たとえば、タスクの起動にはCoherenceの
InvocationServiceなどを使用します。この場合、LoaderInvocableの実装では、memberFileNamesを反復して各ファイルを処理し、その内容をキャッシュにロードする必要があります。通常、クライアント上で実行されるキャッシュ処理は、LoaderInvocableを使用して実行する必要があります。public void load() { NamedCache cache = getCache(); Set members = getStorageMembers(cache); List<String> fileNames = getFileNames(); Map<Member, List<String>> mapWork = divideWork(members, fileNames); InvocationService service = (InvocationService) CacheFactory.getService("InvocationService"); for (Map.Entry<Member, List<String>> entry : mapWork.entrySet()) { Member member = entry.getKey(); List<String> memberFileNames = entry.getValue(); LoaderInvocable task = new LoaderInvocable(memberFileNames, cache.getCacheName()); service.execute(task, Collections.singleton(member), this); } }
親トピック: キャッシュの事前ロード
キャッシュのクリア
NamedCacheインタフェースで定義されるclearまたはtruncateメソッドを使用してクリアできます。clearメソッドを使用すると、メモリーおよびCPUのオーバーヘッドが大きくなる可能性があり、通常、分散キャッシュをクリアすることはお薦めしません。別の方法として、truncateメソッドを使用できます。たとえば:
String key = "k1";
String value = "Hello World!";
NamedCache<Object, Object> cache = CacheFactory.getCache("MyCache");
cache.put(key, value);
System.out.println(cache.get(key));
Cache.truncate;
truncateメソッドでは、メモリーおよびCPUリソースを効率的に使用できるため、大きなキャッシュやリスナーを使用するキャッシュをクリアする場合に最適なオプションになります。truncateメソッドは、フロント・マップおよびバック・マップの両方をクリアするため、ニア・キャッシュのクリアにも最適です。truncateメソッドでエントリが削除されたかどうかは、リスナー、トリガーおよびインターセプタで監視できません。ただし、CacheLifecycleEventイベントが発生し、この操作の実行がすべてのサブスクライバに通知されます。
親トピック: 基本的なキャッシュ操作の実行の実行
キャッシュの解放
CacheFactory.releaseメソッドを使用して、指定されたキャッシュのインスタンスに関連付けられているローカル・リソースを解放するようにしてください。キャッシュを解放すると、そのアプリケーションは使用できなくなりますが、クラスタ全体のキャッシュの内容や、キャッシュに対する他の参照には影響しません。たとえば:
String key = "k1";
String value = "Hello World!";
NamedCache<Object, Object> cache = CacheFactory.getCache("MyCache");
cache.put(key, value);
System.out.println(cache.get(key));
CacheFactory.releaseCache(cache);
親トピック: 基本的なキャッシュ操作の実行の実行
キャッシュの破棄
CacheFactoryクラスを使用して作成されるキャッシュは、CacheFactory.destroyメソッドを使用して破棄できます。destroyメソッドは、指定されたキャッシュをクラスタ全体で破棄します。キャッシュへの参照が無効化され、キャッシュされたデータがクリアされて、すべてのリソースが解放されます。NamedCache.clearメソッドは、分散環境でメモリーとCPUの両方の負荷が高くなるタスクになる可能性があるため、多くの場合destroyメソッドの方が適しています。たとえば:
String key = "k1";
String value = "Hello World!";
NamedCache<Object, Object> cache = CacheFactory.getCache("MyCache");
cache.put(key, value);
System.out.println(cache.get(key));
CacheFactory.destroyCache(cache);
親トピック: 基本的なキャッシュ操作の実行の実行
セッションのクローズ
セッションをクローズするには、closeメソッドを使用します。たとえば:
String key = "k1";
String value = "Hello World!";
try(Session session = Session.create()) {
NamedCache<Object, Object> cache = session.getCache("MyCache");
cache.put(key, value);
System.out.println(cache.get(key));
session.close();
}
catch (Exception e){
}親トピック: 基本的なキャッシュ操作の実行の実行
NameCache操作の非同期実行
com.tangosol.net.AsyncNameCache<K, V>インタフェースにより、キャッシュ操作を並列に完了できます。このインタフェースでは、Java CompletableFutureクラスを使用し、このクラスでは、完了または例外(あるいは両方)のコールバックを提供して、複数の非同期コールを連鎖して順に実行し、パラレルに実行しているすべてのコールが完了するまで待機します。NameCache操作を非同期に実行すると、スループットが改善し、ユーザー・インタフェースの応答性が向上します。Coherenceの例では、非同期キャッシュ操作の実行の追加の例を提供します。Oracle CoherenceのインストールのCoherenceの非同期機能のサンプルを参照してください。
非同期キャッシュ操作を実行するには、CompletableFutureクラスを使用して、Futureインタフェースを実装する必要があります。たとえば:
import com.tangosol.net.AsyncNamedCache;
import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class HelloWorld {
public static void main(String[] args) throws ExecutionException,
InterruptedException {
String key = "k1";
String value = "Hello World!";
NamedCache<Object, Object> cache = CacheFactory.getCache("MyCache");
AsyncNamedCache<Object, Object> as = cache.async();
Future future = as.put(key, value);
future.get();
CompletableFuture cf = as.get(key);
System.out.println(cf.get());
CompletableFuture cfremove = as.remove(key);
System.out.print("Removing key/value: " + cfremove.get() + "\n" );
System.out.println("The key/value is: " + future.get());
}
}
親トピック: 基本的なキャッシュ操作の実行の実行
NameCache型チェックの使用
SessionまたはCacheFactory APIのいずれかを使用している場合、厳密に型指定されたNamedCacheインスタンスをリクエストできます。デフォルトでは、NamedCache<Object, Object>インスタンスが返されます。これは、NamedCacheインスタンスを作成および使用するための最も柔軟なメカニズムですが、キャッシュ・インスタンスとのやり取りに必要なキーと値の型をアプリケーションで設定する必要があります。
次の例では、アプリケーションで使用する任意のタイプのオブジェクトを格納します。
NamedCache<Object,Object> cache = session.getCache("MyCache");
または
NamedCache<Object,Object> cache = CacheFactory.getCache("MyCache");
getCacheメソッドは、型チェックすることなく、必要に応じて特定の型のNamedCacheインスタンスをリクエストする場合に使用できます。TypeAssertionインタフェースは、getCacheメソッドともに使用され、NamedCacheインスタンスで使用されるキーと値の型の正確性をアサートします。このメソッドは、キャッシュがRAW型を使用する必要があることをアサートする場合に使用できます。たとえば:
NamedCache<Object, Object> cache = session.getCache("MyCache",
TypeAssertion.withRawTypes());
同様に、CacheFactoryを使用している場合、
NamedCache<Object, Object> cache = CacheFactory.getCache("MyCache",
TypeAssertion.withRawTypes());
型の安全性を強化するために、キャッシュを作成して、キャッシュで使用されるキーと値の型を明示的にアサートできます。たとえば、キャッシュを作成して、キーと値の型がStringである必要があることをアサートするには、アプリケーションで次を使用できます。
NamedCache<String, String> cache = session.getCache("MyCache",
TypeAssertion.withTypes(String.class, String.class));
NameCacheインスタンスは、アサートされた型に準拠する必要はなく、無視することもできますが、コンパイル時に警告メッセージが表示されます。たとえば:
NamedCache cache = session.getCache("MyCache",
TypeAssertion.withTypes(String.class, String.class));
同様に、RAW型を使用し、ネーム・キャッシュ・インスタンスで特定の型を使用できることをアサートすることを、アプリケーションで選択することもできます。ただし、どちらの場合も、型がチェックされないままでは、エラーが発生することがあります。たとえば:
NamedCache<String, String> cache = session.getCache("MyCache",
TypeAssertion.withRawTypes());
型の安全性を最も強くするには、特定の型をキャッシュ定義の一部として、キャッシュ構成ファイルに宣言することもできます。キャッシュ定義の部分として構成された型と異なる型をアプリケーションが使用すると、ランタイム・エラーが発生します。次の例では、String型のキーと値のみをサポートするキャッシュを構成します。
<cache-mapping> <cache-name>MyCache</cache-name> <scheme-name>distributed</scheme-name> <key-type>String</key-type> <value-type>String</value-type> </cache-mapping>
最後に、明示的な型チェックの無効化をアプリケーションで選択できます。型チェックが無効の場合、型の安全性はアプリケーションで確保する必要があります。
NamedCache<Object, Object> cache = session.getCache("MyCache",
TypeAssertion.withoutTypeChecking());親トピック: 基本的なキャッシュ操作の実行の実行