CQL テンプレート API
CqlTemplate
(Javadoc) クラス (およびそのリアクティブバリアント ReactiveCqlTemplate
(Javadoc) ) は、コア CQL パッケージの中心的なクラスです。リソースの作成と解放を処理します。ステートメントの作成と実行などのコア CQL ワークフローの基本タスクを実行し、CQL の提供と結果の抽出はアプリケーションコードに任せます。CqlTemplate
クラスは、CQL クエリと更新ステートメントを実行し、ResultSet
インスタンスの反復処理と返されたパラメーター値の抽出を実行します。また、CQL 例外をキャッチし、org.springframework.dao
パッケージで定義されている汎用的でより情報量の多い例外階層に変換します。
コードに CqlTemplate
を使用する場合、明確に定義された契約を持つコールバックインターフェースを実装するだけで済みます。CqlSession
が指定されると、PreparedStatementCreator
(Javadoc) コールバックインターフェースは、提供された CQL と必要なパラメーター引数を使用して準備されたステートメントを作成します。RowCallbackHandler
(Javadoc) インターフェースは、ResultSet
の各行から値を抽出します。
CqlTemplate
(Javadoc) は、SessionFactory
(Javadoc) 参照を使用して直接インスタンス化することで DAO 実装内で使用することも、Spring コンテナー内で構成して Bean 参照として DAO に提供することもできます。CqlTemplate
は、CassandraTemplate
の基本的な構成要素です。
このクラスによって発行されたすべての CQL は、テンプレートインスタンスの完全修飾クラス名に対応するカテゴリの DEBUG
レベルでログに記録されます (通常は CqlTemplate
ですが、CqlTemplate
クラスのカスタムサブクラスを使用する場合は異なる場合があります)。
CQL API インスタンスで CqlTemplate
(Javadoc) 、AsyncCqlTemplate
(Javadoc) 、ReactiveCqlTemplate
(Javadoc) の各パラメーターを構成することで、フェッチサイズ、一貫性レベル、再試行ポリシーのデフォルトを制御できます。特定のクエリオプションが設定されていない場合は、デフォルトが適用されます。
CqlTemplate にはさまざまな実行モデルがあります。基本的な CqlTemplate はブロッキング実行モデルを使用します。非同期実行および ListenableFuture インスタンスとの同期には AsyncCqlTemplate を使用でき、リアクティブ実行には ReactiveCqlTemplate を使用できます。 |
CqlTemplate
クラスの使用例
このセクションでは、CqlTemplate
クラスの動作例をいくつか示します。これらの例は、CqlTemplate
によって公開されるすべての機能の完全なリストではありません。これについては、Javadoc を参照してください。
CqlTemplate
によるクエリ (SELECT)
次のクエリはテーブル内の行数を取得します。
命令的
リアクティブ
int rowCount = cqlTemplate.queryForObject("SELECT COUNT(*) FROM t_actor", Integer.class);
Mono<Integer> rowCount = reactiveCqlTemplate.queryForObject("SELECT COUNT(*) FROM t_actor", Integer.class);
次のクエリはバインド変数を使用します。
命令的
リアクティブ
int countOfActorsNamedJoe = cqlTemplate.queryForObject(
"SELECT COUNT(*) FROM t_actor WHERE first_name = ?", Integer.class, "Joe");
Mono<Integer> countOfActorsNamedJoe = reactiveCqlTemplate.queryForObject(
"SELECT COUNT(*) FROM t_actor WHERE first_name = ?", Integer.class, "Joe");
次の例では、String
をクエリします。
命令的
リアクティブ
String lastName = cqlTemplate.queryForObject(
"SELECT last_name FROM t_actor WHERE id = ?",
String.class, 1212L);
Mono<String> lastName = reactiveCqlTemplate.queryForObject(
"SELECT last_name FROM t_actor WHERE id = ?",
String.class, 1212L);
次の例では、単一のドメインオブジェクトをクエリして値を設定します。
命令的
リアクティブ
Actor actor = cqlTemplate.queryForObject("SELECT first_name, last_name FROM t_actor WHERE id = ?",
new RowMapper<Actor>() {
public Actor mapRow(Row row, int rowNum) {
Actor actor = new Actor();
actor.setFirstName(row.getString("first_name"));
actor.setLastName(row.getString("last_name"));
return actor;
}
}, 1212L);
Mono<Actor> actor = reactiveCqlTemplate.queryForObject(
"SELECT first_name, last_name FROM t_actor WHERE id = ?",
new RowMapper<Actor>() {
public Actor mapRow(Row row, int rowNum) {
Actor actor = new Actor();
actor.setFirstName(row.getString("first_name"));
actor.setLastName(row.getString("last_name"));
return actor;
}},
1212L);
次の例では、複数のドメインオブジェクトをクエリして値を設定します。
命令的
リアクティブ
List<Actor> actors = cqlTemplate.query(
"SELECT first_name, last_name FROM t_actor",
new RowMapper<Actor>() {
public Actor mapRow(Row row, int rowNum) {
Actor actor = new Actor();
actor.setFirstName(row.getString("first_name"));
actor.setLastName(row.getString("last_name"));
return actor;
}
});
Flux<Actor> actors = reactiveCqlTemplate.query(
"SELECT first_name, last_name FROM t_actor",
new RowMapper<Actor>() {
public Actor mapRow(Row row, int rowNum) {
Actor actor = new Actor();
actor.setFirstName(row.getString("first_name"));
actor.setLastName(row.getString("last_name"));
return actor;
}
});
コードの最後の 2 つのスニペットが実際に同じアプリケーションに存在する場合、2 つの RowMapper
匿名内部クラスに存在する重複を削除し、単一のクラス (通常は static
ネストされたクラス) に抽出して参照できるようにするのが合理的です。DAO メソッドによる。
例: 最後のコードスニペットを次のように記述した方がよい場合があります。
命令的
リアクティブ
List<Actor> findAllActors() {
return cqlTemplate.query("SELECT first_name, last_name FROM t_actor", ActorMapper.INSTANCE);
}
enum ActorMapper implements RowMapper<Actor> {
INSTANCE;
public Actor mapRow(Row row, int rowNum) {
Actor actor = new Actor();
actor.setFirstName(row.getString("first_name"));
actor.setLastName(row.getString("last_name"));
return actor;
}
}
Flux<Actor> findAllActors() {
return reactiveCqlTemplate.query("SELECT first_name, last_name FROM t_actor", ActorMapper.INSTANCE);
}
enum ActorMapper implements RowMapper<Actor> {
INSTANCE;
public Actor mapRow(Row row, int rowNum) {
Actor actor = new Actor();
actor.setFirstName(row.getString("first_name"));
actor.setLastName(row.getString("last_name"));
return actor;
}
}
INSERT
、UPDATE
、DELETE
と CqlTemplate
execute(…)
メソッドを使用して、INSERT
、UPDATE
、DELETE
操作を実行できます。パラメーター値は通常、変数引数として、またはオブジェクト配列として提供されます。
次の例は、CqlTemplate
を使用して INSERT
操作を実行する方法を示しています。
命令的
リアクティブ
cqlTemplate.execute(
"INSERT INTO t_actor (first_name, last_name) VALUES (?, ?)",
"Leonor", "Watling");
Mono<Boolean> applied = reactiveCqlTemplate.execute(
"INSERT INTO t_actor (first_name, last_name) VALUES (?, ?)",
"Leonor", "Watling");
次の例は、CqlTemplate
を使用して UPDATE
操作を実行する方法を示しています。
命令的
リアクティブ
cqlTemplate.execute(
"UPDATE t_actor SET last_name = ? WHERE id = ?",
"Banjo", 5276L);
Mono<Boolean> applied = reactiveCqlTemplate.execute(
"UPDATE t_actor SET last_name = ? WHERE id = ?",
"Banjo", 5276L);
次の例は、CqlTemplate
を使用して DELETE
操作を実行する方法を示しています。
命令的
リアクティブ
cqlTemplate.execute(
"DELETE FROM t_actor WHERE id = ?",
5276L);
Mono<Boolean> applied = reactiveCqlTemplate.execute(
"DELETE FROM actor WHERE id = ?",
actorId);
その他の CqlTemplate
操作
execute(..)
メソッドを使用して、任意の CQL を実行できます。結果として、このメソッドは DDL ステートメントによく使用されます。コールバックインターフェースを取得したり、変数配列をバインドしたりするバリアントで大幅にオーバーロードになっています。
次の例は、execute()
メソッドに渡されるさまざまな API オブジェクトを使用してテーブルを作成および削除する方法を示しています。
cqlTemplate.execute("CREATE TABLE test_table (id uuid primary key, event text)");
DropTableSpecification dropper = DropTableSpecification.dropTable("test_table");
String cql = DropTableCqlGenerator.toCql(dropper);
cqlTemplate.execute(cql);
Cassandra 接続の制御
アプリケーションは、CqlSession
オブジェクトを使用して Apache Cassandra に接続します。Cassandra CqlSession
は、個々のノードへの複数の接続を追跡し、スレッドセーフで長期間存続するオブジェクトとして設計されています。通常、アプリケーション全体で 1 つの CqlSession
を使用できます。
Spring は、SessionFactory
を介して Cassandra CqlSession
を取得します。SessionFactory
は、Apache Cassandra の Spring Data の一部であり、汎用化された接続ファクトリです。これにより、コンテナーまたはフレームワークは、接続処理とルーティングの課題をアプリケーションコードから隠すことができます。
次の例は、デフォルトの SessionFactory
を設定する方法を示しています。
命令的
リアクティブ
CqlSession session = … // get a Cassandra Session
CqlTemplate template = new CqlTemplate();
template.setSessionFactory(new DefaultSessionFactory(session));
CqlSession session = … // get a Cassandra Session
ReactiveCqlTemplate template = new ReactiveCqlTemplate(new DefaultBridgedReactiveSession(session));
CqlTemplate
およびその他のテンプレート API 実装は、操作ごとに CqlSession
を取得します。セッションは存続期間が長いため、目的の操作を呼び出した後も閉じられません。リソースを適切に破棄する責任は、セッションを使用するコンテナーまたはフレームワークにあります。
org.springframework.data.cassandra.core.cql.session
パッケージ内にはさまざまな SessionFactory
実装があります。
例外変換
Spring Framework は、さまざまなデータベースおよびマッピングテクノロジの例外変換を提供します。これは、従来、JDBC および JPA を対象としていました。Apache Cassandra 用の Spring Data は、org.springframework.dao.support.PersistenceExceptionTranslator
インターフェースの実装を提供することで、この機能を Apache Cassandra に拡張します。
Spring の一貫したデータアクセス例外階層へのマッピングの背後にある目的は、特定の Cassandra 例外に対するコーディングや処理に頼ることなく、移植可能で記述的な例外処理コードを作成できるようにすることです。Spring のデータアクセス例外はすべて DataAccessException
クラスから継承されるため、データベース関連のすべての例外を 1 つの try-catch ブロック内で確実にキャッチできます。
ReactiveCqlTemplate
および ReactiveCassandraTemplate
は、できるだけ早く例外を伝播します。リアクティブシーケンスの処理中に発生する例外は、エラーシグナルとして出力されます。