DATACASS-510 - Introduce support for prepared statements using CassandraTemplate.

We now support prepared statement usage through CassandraTemplate and its asynchronous and reactive variants. All statements created or received by CassandraTemplate will be prepared. CassandraTemplate is an infrastructure class for repositories so prepared statements will affect repositories, too.
This commit is contained in:
Mark Paluch
2020-12-03 17:07:15 +01:00
parent 529e0692e6
commit ed46d742eb
32 changed files with 934 additions and 189 deletions

View File

@@ -3,6 +3,11 @@
This chapter summarizes changes and new features for each release.
[[new-features.3-2-0]]
== What's new in Spring Data for Apache Cassandra 3.2
* <<cassandra.template.prepared-statements,Support for prepared statements>> using `CassandraTemplate` and repositories (enabled by default).
[[new-features.3-1-0]]
== What's new in Spring Data for Apache Cassandra 3.1

View File

@@ -3,6 +3,7 @@
This chapter covers the details of the Spring Data Repository support for Apache Cassandra.
Cassandra's repository support builds on the core repository support explained in "`<<repositories>>`".
Cassandra repositories use `CassandraTemplate` and its wired `CqlTemplate` as infrastructure beans.
You should understand the basic concepts explained there before proceeding.
[[cassandra-repo-usage]]

View File

@@ -520,7 +520,7 @@ The `CqlTemplate` class executes CQL queries and update statements, performs ite
It also catches CQL exceptions and translates them to the generic, more informative, exception hierarchy defined in the `org.springframework.dao` package.
When you use the `CqlTemplate` for your code, you need only implement callback interfaces, which have a clearly defined contract.
Given a `Connection`, the `PreparedStatementCreator` callback interface creates a prepared statement with the provided CQL and any necessary parameter arguments.
Given a `Connection`, the `PreparedStatementCreator` callback interface creates a <<cassandra.template.prepared-statements.cql,prepared statement>> with the provided CQL and any necessary parameter arguments.
The `RowCallbackHandler` interface extracts values from each row of a `ResultSet`.
The `CqlTemplate` can be used within a DAO implementation through direct instantiation with a `SessionFactory` reference or be configured in the Spring container and given to DAOs as a bean reference. `CqlTemplate` is a foundational building block for <<cassandra-template,`CassandraTemplate`>>.
@@ -1118,3 +1118,78 @@ The terminating methods (`first()`, `one()`, `all()`, and `stream()`) handle swi
WARNING: The new fluent template API methods (that is, `query(..)`, `insert(..)`, `update(..)`, and `delete(..)`) use effectively thread-safe supporting objects to compose the CQL statement.
However, it comes at the added cost of additional young-gen JVM heap overhead, since the design is based on final fields for the various CQL statement components and construction on mutation.
You should be careful when possibly inserting or deleting a large number of objects (such as inside of a loop, for instance).
[[cassandra.template.prepared-statements]]
== Prepared Statements
CQL statements that are executed multiple times can be prepared and stored in a `PreparedStatement` object to improve query performance.
Both, the driver and Cassandra maintain a mapping of `PreparedStatement` queries to their metadata.
You can use prepared statements through the following abstractions:
* `CqlTemplate` through the choice of API
* `CassandraTemplate` by enabling prepared statements
* Cassandra repositories as they are built on `CassandraTemplate`
[[cassandra.template.prepared-statements.cql]]
=== Using `CqlTemplate`
The `CqlTemplate` class (and its asynchronous and reactive variants) offers various methods accepting static CQL, `Statement` objects and `PreparedStatementCreator`.
Methods accepting static CQL without additional arguments typically run the CQL statement as-is without further processing.
Methods accepting static CQL in combination with an arguments array (such as `execute(String cql, Object... args)` and `queryForRows(String cql, Object... args)`) use prepared statements.
Internally, these methods create a `PreparedStatementCreator` and `PreparedStatementBinder` objects to prepare the statement and later on to bind values to the statement to run it.
Spring Data Cassandra generally uses index-based parameter bindings for prepared statements.
Since Cassandra Driver version 4, prepared statements are cached on the driver level which removes the need to keep track of prepared statements in the application.
The following example shows how to issue a query with a parametrized prepared statement:
====
[source,java,indent=0]
----
include::../{example-root}/CqlTemplateExamples.java[tags=lastName]
----
====
In cases where you require more control over statement preparation and parameter binding (for example, using named binding parameters), you can fully control prepared statement creation and parameter binding by calling query methods with `PreparedStatementCreator` and `PreparedStatementBinder` arguments:
====
[source,java,indent=0]
----
include::../{example-root}/CqlTemplateExamples.java[tags=preparedStatement]
----
====
Spring Data Cassandra ships with classes supporting that pattern in the `cql` package:
* `SimplePreparedStatementCreator` - utility class to create a prepared statement.
* `ArgumentPreparedStatementBinder` - utility class to bind arguments to a prepared statement.
[[cassandra.template.prepared-statements.cassandra-template]]
=== Using `CassandraTemplate`
The `CassandraTemplate` class is built on top of `CqlTemplate` to provide a higher level of abstraction.
The use of prepared statements can be controlled directly on `CassandraTemplate` (and its asynchronous and reactive variants) by calling `setUsePreparedStatements(false)` respective `setUsePreparedStatements(true)`.
Note that the use of prepared statements by `CassandraTemplate` is enabled by default.
The following example shows the use of methods that generate and that accept CQL:
====
[source,java,indent=0]
----
include::../{example-root}/CassandraTemplateExamples.java[tags=preparedStatement]
----
====
Calling entity-bound methods such as `select(Query, Class<T>)` or `update(Query, Update, Class<T>)` build CQL statements themselves to perform the intended operations.
Some `CassandraTemplate` methods (such as `select(Statement<?>, Class<T>)`) also accepts CQL `Statement` objects as part of their API.
It's possible to participate in prepared statements when calling methods accepting a `Statement` with a `SimpleStatement` object.
The template API extracts the query string and parameters (positional and named parameters) and uses these to prepare, bind, and run the statement.
Non-``SimpleStatement`` objects cannot be used with prepared statements.
[[cassandra.template.prepared-statements.caching]]
=== Caching Prepared Statements
Since Cassandra driver 4.0, prepared statements are cached by the `CqlSession` cache so it is okay to prepare the same string twice.
Previous versions required caching of prepared statements outside of the driver.
See also the https://docs.datastax.com/en/developer/java-driver/latest/manual/core/statements/prepared/[Driver documentation on Prepared Statements] for further reference.

View File

@@ -4,6 +4,8 @@
This chapter outlines the specialties handled by the reactive repository support for Apache Cassandra.
It builds on the core repository infrastructure explained in <<cassandra.repositories>>, so you should have a good understanding of the basic concepts explained there.
Cassandra repositories use `ReactiveCassandraTemplate` and its wired `ReactiveCqlTemplate` as infrastructure beans.
Reactive usage is broken up into two phases: Composition and Execution.
Calling repository methods lets you compose a reactive sequence by obtaining `Publisher` instances and applying operators.

View File

@@ -150,7 +150,7 @@ The `ReactiveCqlTemplate` class runs CQL queries and update statements and perfo
It also catches CQL exceptions and translates them into the generic, more informative, exception hierarchy defined in the `org.springframework.dao` package.
When you use the `ReactiveCqlTemplate` in your code, you need only implement callback interfaces, which have a clearly defined contract.
Given a `Connection`, the `ReactivePreparedStatementCreator` callback interface creates a prepared statement with the provided CQL and any necessary parameter arguments.
Given a `Connection`, the `ReactivePreparedStatementCreator` callback interface creates a <<cassandra.template.prepared-statements.cql,prepared statement>> with the provided CQL and any necessary parameter arguments.
The `RowCallbackHandler`
interface extracts values from each row of a `ReactiveResultSet`.