準備されたステートメント

複数回実行される CQL ステートメントを準備して PreparedStatement オブジェクトに保存すると、クエリのパフォーマンスが向上します。ドライバーと Cassandra は両方とも、PreparedStatement クエリのメタデータへのマッピングを維持します。次の抽象化を通じて準備されたステートメントを使用できます。

CqlTemplate を使用する

CqlTemplate クラス (およびその非同期およびリアクティブなバリアント) は、静的 CQL、Statement オブジェクト、および PreparedStatementCreator を受け入れるさまざまなメソッドを提供します。追加の引数なしで静的 CQL を受け入れるメソッドは通常、それ以上の処理を行わずに CQL ステートメントをそのまま実行します。引数配列と組み合わせて静的 CQL を受け入れるメソッド ( execute(String cql, Object…​ args) や queryForRows(String cql, Object…​ args) など) は、準備されたステートメントを使用します。内部的には、これらのメソッドは PreparedStatementCreator オブジェクトと PreparedStatementBinder オブジェクトを作成してステートメントを準備し、後でステートメントを実行するために値をステートメントにバインドします。Spring Data Cassandra は通常、準備されたステートメントにインデックスベースのパラメーターバインディングを使用します。

Cassandra ドライバーバージョン 4 以降、プリペアドステートメントはドライバーレベルでキャッシュされるため、アプリケーションでプリペアドステートメントを追跡する必要がなくなります。

次の例は、パラメーター化されたプリペアドステートメントを使用してクエリを発行する方法を示しています。

  • 命令的

  • リアクティブ

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);

ステートメントの準備とパラメーターのバインドをさらに制御する必要がある場合 (たとえば、名前付きバインディングパラメーターを使用する)、PreparedStatementCreator および PreparedStatementBinder 引数を指定してクエリメソッドを呼び出すことで、準備されたステートメントの作成とパラメーターのバインドを完全に制御できます。

  • 命令的

  • リアクティブ

List<String> lastNames = cqlTemplate.query(
		session -> session.prepare("SELECT last_name FROM t_actor WHERE id = ?"),
		ps -> ps.bind(1212L),
		(row, rowNum) -> row.getString(0));
Flux<String> lastNames = reactiveCqlTemplate.query(
		session -> session.prepare("SELECT last_name FROM t_actor WHERE id = ?"),
		ps -> ps.bind(1212L),
		(row, rowNum) -> row.getString(0));

Spring Data Cassandra には、cql パッケージでそのパターンをサポートするクラスが同梱されています。

  • SimplePreparedStatementCreator - 準備されたステートメントを作成するユーティリティクラス。

  • ArgumentPreparedStatementBinder - 準備されたステートメントに引数をバインドするユーティリティクラス。

CassandraTemplate を使用する

CassandraTemplate クラスは CqlTemplate 上に構築され、より高いレベルの抽象化を提供します。準備されたステートメントの使用は、setUsePreparedStatements(false) および setUsePreparedStatements(true) をそれぞれ呼び出すことによって、CassandraTemplate (およびその非同期およびリアクティブなバリアント) 上で直接制御できます。CassandraTemplate による準備済みステートメントの使用はデフォルトで有効になっていることに注意してください。

次の例は、CQL を生成および受け入れるメソッドの使用箇所を示しています。

  • 命令的

  • リアクティブ

template.setUsePreparedStatements(true);

Actor actorByQuery = template.selectOne(query(where("id").is(42)), Actor.class);

Actor actorByStatement = template.selectOne(
		SimpleStatement.newInstance("SELECT id, name FROM actor WHERE id = ?", 42),
		Actor.class);
template.setUsePreparedStatements(true);

Mono<Actor> actorByQuery = template.selectOne(query(where("id").is(42)), Actor.class);

Mono<Actor> actorByStatement = template.selectOne(
		SimpleStatement.newInstance("SELECT id, name FROM actor WHERE id = ?", 42),
		Actor.class);

select(Query, Class<T>) や update(Query, Update, Class<T>) などのエンティティバインドメソッドを呼び出すと、CQL ステートメント自体が構築され、目的の操作が実行されます。一部の CassandraTemplate メソッド ( select(Statement<?>, Class<T>) など) は、API の一部として CQL Statement オブジェクトも受け入れます。

Statement を SimpleStatement オブジェクトで受け入れるメソッドを呼び出すときに、準備されたステートメントに参加することができます。テンプレート API はクエリ文字列とパラメーター (位置パラメーターと名前付きパラメーター) を抽出し、これらを使用してステートメントを準備、バインド、実行します。非 SimpleStatement オブジェクトは、準備されたステートメントでは使用できません。

プリペアドステートメントのキャッシュ

Cassandra ドライバー 4.0 以降、準備されたステートメントは CqlSession キャッシュによってキャッシュされるため、同じ文字列を 2 回準備しても問題ありません。以前のバージョンでは、ドライバーの外部で準備されたステートメントをキャッシュする必要がありました。詳細については、プリペアドステートメントに関するドライバードキュメント (英語) も参照してください。