Overview of the Cassandra CQL API
Class/Interface | Description |
---|---|
|
Resource adaptor provider interface used to:
|
|
SLEE activity type used to:
There are also convenience operations to:
|
|
Represents an executable cassandra query. This is the super-type for |
|
A statement that has been 'prepared' by the cassandra database. Such statements have been pre-parsed and validated by the database. A prepared statement can be executed once concrete values have been provided for the bind variables (to make a bound statement). A prepared statement also allows you to define default values for properties such as the Consistency level or tracing. Such default values are used in any bound statement created from the prepared statement. |
|
A prepared statement for which all bind variables have been bound to values. |
|
A group of statements that will be executed together as a 'batch' by the cassandra database. |
|
The result of a query against the cassandra database. Used to:
|
|
A row in a result set. Used to get values in the row by position, or name. |
Examples
Getting the Cassandra CQL provider
You get the Cassandra CQL provider object from JNDI
. For example, consider a service with the following @RATypeBinding
:
@RATypeBinding(
raType = @ComponentId(name = "cassandra-cql-ratype",
vendor = "OpenCloud",
version = "1.0.0"),
activityContentInterfaceFactoryName =
"cassandra-cql-ra/activitycontextinterfacefactory",
resourceAdaptorEntityLink = "cassandra-cql-ra",
resourceAdaptorObjectName = "cassandra-cql-ra/provider"
)
Then an SBB
might include code such as the following in setSbbContext()
.
@Override
public void setSbbContext(SbbContext context) {
try {
final Context env = (Context) new InitialContext().lookup("java:comp/env");
this.cassandraCQLProvider =
(CassandraCQLProvider) env.lookup("cassandra-cql-ra/provider");
this.cassandraCQLACIFactory =
(CassandraCQLActivityContextInterfaceFactory)
env.lookup("cassandra-cql-ra/activitycontextinterfacefactory");
}
catch (NamingException e) {
throw new RuntimeException("Failed Cassandra provider + ACI factory lookup", e);
}
}
Preparing statements
A prepared statement is a cassandra query that has been pre-parsed and validated by the cassandra database. Ideally you prepare a query once, and then use it many times by binding values to binding variables in the query. The cassandra CQL RA manages a cache of prepared statements so you do not need to implement any type of caching yourself. This saves compute resources on the database, avoids needless network interaction with the database and minimises the time the application will block and wait during prepare.
final String query = "SELECT * FROM users WHERE lastname='Page'";
final PreparedCassandraStatement preparedQuery = cassandraCQLProvider.prepare(query);
You may also prepare statements via the prepare operation of the |
Binding values to variables
A bound statement is a prepared statement with values bound to the bind variables. The values of a bound statement can be set by either index or name. If multiple bind variables have the same name, setting that name will set all the variables for that name.
All the variables of the statement must be bound before it can be executed. If you don’t explicitly set a value for a variable, a CassandraException
will be thrown when submitting the statement. If you want to set a variable to null
, use the setToNull
operation.
There are two options for creating a bound statement from a prepared statement:
-
Use
bind()
final BoundCassandraStatement boundStatement = preparedStatement.bind();
-
Use
bind(Object… values)
final BoundCassandraStatement boundStatement = preparedStatement.bind(firstValue, secondValue, thirdValue);
Use the set
operations of BoundCassandraStatement
to bind any remaining variables to values. There are two variants of each set
operation, one which takes an index, and one which takes a name.
boundStatement.setString("firstname", "David").setString("lastname", "Page");
Use the |
Using a batch statement
A batch statement is a group of queries that you wish to execute together in the cassandra database. Typically these queries are related, from a business logic perspective.
There are two steps to using a batch statement:
-
Create a batch statement with the
createBatchStatement
operation of the provider.// create a new batch statement final BatchCassandraStatement batchStatement = cassandraCQLProvider.createBatchStatement()
-
Add queries to the batch statement with the
add
andaddAll
operations.// add statements to the batch statement batchStatement.add(firstBoundStatement); batchStatement.addAll(boundStatementList);
The options of the added statement such as consistency level, fetch size, tracing, will be ignored for the purpose of the execution of the Batch. Instead, the options used are the ones defined by the batch statement.
Once the batch statement is built, you can then execute it synchronously or asynchronously.
Executing synchronous queries
Queries are executed synchronously by using operations on the provider. There are three variants:
-
Execute a query
CassandraResultSet execute(String query) throws CassandraException;
-
Execute a query, with arguments
CassandraResultSet execute(String query, Object... values) throws CassandraException;
-
Execute a statement
CassandraResultSet execute(CassandraStatement st) throws CassandraException;
There is an overloaded version of each operation that takes timeout arguments as well. The resource adaptor will throw a CassandraException
if execute blocks longer than the timeout. For example:
CassandraResultSet execute(long timeout, TimeUnit units, String query) throws CassandraException;
We strongly recommend you use the version of the synchronous operations with a timeout, or use the asynchronous operations. Otherwise a failure on the cassandra database could cause all event router threads to become blocked, waiting on the cassandra database. |
Creating a CassandraSession for asynchronous queries
The result of an asynchronous query, or a request for additional results in a result set, are received as events that are associated with an activity called the CassandraSession
. You use the Cassandra CQL provider to create a new session. You use an ActivityContextInterface
factory to get the ActivityContextInterface
associated with the activity so you can attach to it. and thereafter receive any events associated with the activity. See the following example.
final CassandraSession session = cassandraCQLProvider.newSession();
final ActivityContextInterface sessionACI =
cassandraCQLACIFactory.getActivityContextInterface(session);
sessionACI.attach(context.getSbbLocalObject());
The Cassandra CQL provider will always return a CassandraSession
object. In an overload or an error situation the CassaandraSession
returned may not be valid and will fail any requests you make by throwing a CassandraException
. You can test if the CassandraSession
is valid with the isValid()
operation.
final CassandraSession session = cassandraCQLProvider.newSession();
if (session.isValid()) {
// if this is a valid 'session' then attach to the ACI.
ActivityContextInterface sessionACI =
cassandraCQLACIFactory.getActivityContextInterface(session);
sessionACI.attach(context.getSbbLocalObject());
}
Consider incrementing a statistic to record such an error. You could also define a threshold alarm that is a function of such a statistic. |
Executing asynchronous queries
Queries are executed asynchronously by using operations on CassandraSession
. There are three variants:
-
Execute a query
void execute(String query) throws CassandraException;
-
Execute a query, with arguments
void execute(String query, Object... values) throws CassandraException;
-
Execute a statement
void execute(CassandraStatement st) throws CassandraException;
The result (a CassandraResultSet
) will be received in a future SLEE transaction as a QueryResultEvent
.
Getting all the results in a result set
If a query will result in a large number of rows in the result set, then the results will be received as a number of pages.
You can control the fetch size on a per query basis by using the setFetchSize() operation on CassandraStatement
|
You request the next page of results in a result set by using the fetchMoreResults()
operation of CassandraResultSet
. The next page of results will be received in a subsequent SLEE transaction as a QueryResultEvent
(event if the initial query was executed synchronously).
public interface CassandraResultSet extends Iterable<CassandraRow> {
// ...
/**
* Fetch the next page of results in the result set.
* @param session session upon which subsequent results will be delivered
* @return true if more results will be fetched,
* false if all results have already been fetched
* @throws CassandraException if there is a failure requesting more results
*/
boolean fetchMoreResults(CassandraSession session) throws CassandraException;
// ...
}
Use the isFullyFetched() operation of CassandraResultSet to test if all results in a result set have been fetched.
|