Scylla Documentation Logo Documentation
  • Server
    • Scylla Open Source
    • Scylla Enterprise
    • Scylla Alternator
  • Cloud
    • Scylla Cloud
    • Scylla Cloud Docs
  • Tools
    • Scylla Manager
    • Scylla Monitoring Stack
    • Scylla Operator
  • Drivers
    • CQL Drivers
    • DynamoDB Drivers
Download
Menu
Scylla Java Driver Manual Core driver Statements Per-query keyspace

Per-query keyspace¶

Quick overview¶

Specify the keyspace separately instead of hardcoding it in the query string.

  • Cassandra 4+ / DSE 6+.

  • only works with simple statements.


Sometimes it is convenient to send the keyspace separately from the query string, and without switching the whole session to that keyspace either. For example, you might have a multi-tenant setup where identical requests are executed against different keyspaces.

This feature is only available with Cassandra 4.0 or above (CASSANDRA-10145). Make sure you are using native protocol v5 or above to connect.

If you try against an older version, you will get an error:

Exception in thread "main" java.lang.IllegalArgumentException: Can't use per-request keyspace with protocol V4

Note: at the time of writing, Cassandra 4 is not released yet. If you want to test those examples against the development version, keep in mind that native protocol v5 is still in beta, so you’ll need to force it in the configuration: datastax-java-driver.protocol.version = V5.

Basic usage¶

To use a per-query keyspace, set it on your statement instance:

CqlSession session = CqlSession.builder().build();
CqlIdentifier keyspace = CqlIdentifier.fromCql("test");
SimpleStatement statement =
    SimpleStatement.newInstance("SELECT * FROM foo WHERE k = 1").setKeyspace(keyspace);
session.execute(statement);

You can do this on simple, prepared or batch statements.

If the session is connected to another keyspace, the per-query keyspace takes precedence:

CqlIdentifier keyspace1 = CqlIdentifier.fromCql("test1");
CqlIdentifier keyspace2 = CqlIdentifier.fromCql("test2");

CqlSession session = CqlSession.builder().withKeyspace(keyspace1).build();

// Will query test2.foo:
SimpleStatement statement =
    SimpleStatement.newInstance("SELECT * FROM foo WHERE k = 1").setKeyspace(keyspace2);
session.execute(statement);

On the other hand, if a keyspace is hard-coded in the query, it takes precedence over the per-query keyspace:

// Will query test1.foo:
SimpleStatement statement =
    SimpleStatement.newInstance("SELECT * FROM test1.foo WHERE k = 1").setKeyspace(keyspace2);

Bound statements¶

Bound statements can’t have a per-query keyspace; they only inherit the one that was set on the prepared statement:

CqlIdentifier keyspace = CqlIdentifier.fromCql("test");
PreparedStatement pst =
    session.prepare(
        SimpleStatement.newInstance("SELECT * FROM foo WHERE k = ?").setKeyspace(keyspace));

// Will query test.foo:
BoundStatement bs = pst.bind(1);

The rationale is that prepared statements hold metadata about the target table; if Cassandra allowed execution against different keyspaces, it would be under the assumption that all tables have the same exact schema, which could create issues if this turned out not to be true at runtime.

Therefore you’ll have to prepare against every target keyspace. A good strategy is to do this lazily with a cache. Here is a simple example using Guava:

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

LoadingCache<CqlIdentifier, PreparedStatement> cache =
    CacheBuilder.newBuilder()
        .build(
            new CacheLoader<CqlIdentifier, PreparedStatement>() {
              @Override
              public PreparedStatement load(CqlIdentifier keyspace) throws Exception {
                return session.prepare(
                    SimpleStatement.newInstance("SELECT * FROM foo WHERE k = ?")
                        .setKeyspace(keyspace));
              }
            });
CqlIdentifier keyspace = CqlIdentifier.fromCql("test");
BoundStatement bs = cache.get(keyspace).bind(1);

Relation to the routing keyspace¶

Statements have another keyspace-related method: Statement.setRoutingKeyspace(). However, the routing keyspace is only used for token-aware routing, as a hint to help the driver send requests to the best replica. It does not affect the query string itself.

If you are using a per-query keyspace, the routing keyspace becomes obsolete: the driver will use the per-query keyspace as the routing keyspace.

SimpleStatement statement =
    SimpleStatement.newInstance("SELECT * FROM foo WHERE k = 1")
       .setKeyspace(keyspace)
       .setRoutingKeyspace(keyspace); // NOT NEEDED: will be ignored

At some point in the future, when Cassandra 4 becomes prevalent and using a per-query keyspace is the norm, we’ll probably deprecate setRoutingKeyspace().

PREVIOUS
Batch statements
NEXT
Prepared statements
  • 4.13.0.x
    • 4.13.0.x
    • 4.12.0.x
    • 4.11.1.x
    • 4.10.0.x
    • 4.7.2.x
    • 3.11.2.x
    • 3.11.0.x
    • 3.10.2.x
    • 3.7.2.x
  • Java Driver for Scylla and Apache Cassandra®
  • API Documentation
  • Manual
    • API conventions
    • Case sensitivity
    • Core driver
      • Address resolution
      • Asynchronous programming
      • Authentication
      • Bill of Materials (BOM)
      • Compression
      • Configuration
        • Reference configuration
      • Control connection
      • Custom codecs
      • Detachable types
      • Using the driver in GraalVM native images
      • Query idempotence
      • Integration
      • Load balancing
      • Logging
      • Metadata
        • Node metadata
        • Schema metadata
        • Token metadata
      • Metrics
      • Native protocol
      • Non-blocking programming
      • Paging
      • Performance
      • Connection pooling
      • Query timestamps
      • Reactive Style Programming
      • Reconnection
      • Request tracker
      • Retries
      • Using the shaded JAR
      • Speculative query execution
      • SSL
      • Statements
        • Batch statements
        • Per-query keyspace
        • Prepared statements
        • Simple statements
      • Temporal types
      • Request throttling
      • Query tracing
      • Tuples
      • User-defined types
    • Developer docs
      • Administrative tasks
      • Common infrastructure
        • Concurrency
        • Driver context
        • Event bus
      • Native protocol layer
      • Netty pipeline
      • Request execution
    • Mapper
      • Integration
        • Kotlin
        • Lombok
        • Java 14 Records
        • Scala
      • DAOs
        • Custom result types
        • Delete methods
        • GetEntity methods
        • Increment methods
        • Insert methods
        • Null saving strategy
        • Query methods
        • Query provider methods
        • Select methods
        • SetEntity methods
        • Statement attributes
        • Update methods
      • Entities
      • Mapper interface
    • OSGi
    • Query builder
      • Conditions
      • DELETE
      • Idempotence in the query builder
      • INSERT
      • Relations
      • Schema builder
        • Aggregate
        • Function
        • Index
        • Keyspace
        • Materialized View
        • Table
        • Type
      • SELECT
      • Terms
      • TRUNCATE
      • UPDATE
  • Upgrade guide
  • Frequently asked questions
  • Changelog
  • Create an issue
  • Edit this page

On this page

  • Per-query keyspace
    • Quick overview
    • Basic usage
    • Bound statements
    • Relation to the routing keyspace
Logo
Docs Contact Us About Us
Mail List Icon Slack Icon
© 2022, ScyllaDB. All rights reserved.
Last updated on 25 May 2022.
Powered by Sphinx 4.3.2 & ScyllaDB Theme 1.2.2