Cassandra Java Driver
The DataStax Java Driver is the official library for connecting Java applications to Apache Cassandra. It handles connection pooling, load balancing, retry logic, and serialization of CQL statements and results. The current major version is Driver 4.x, which uses a modern, fluent API built on Java 8+ features.
Adding the Driver to Your Project
Maven
<dependency> <groupId>com.datastax.oss</groupId> <artifactId>java-driver-core</artifactId> <version>4.17.0</version> </dependency>
Gradle
implementation 'com.datastax.oss:java-driver-core:4.17.0'
Connecting to Cassandra
import com.datastax.oss.driver.api.core.CqlSession;
import java.net.InetSocketAddress;
CqlSession session = CqlSession.builder()
.addContactPoint(new InetSocketAddress("127.0.0.1", 9042))
.withLocalDatacenter("datacenter1")
.withKeyspace("ecommerce")
.build();
System.out.println("Connected: " + session.getKeyspace());
session.close();
Connecting with Authentication
CqlSession session = CqlSession.builder()
.addContactPoint(new InetSocketAddress("10.0.0.1", 9042))
.withLocalDatacenter("us-east")
.withAuthCredentials("alice", "Al1ce$ecure!")
.withKeyspace("ecommerce")
.build();
Executing Simple Queries
import com.datastax.oss.driver.api.core.cql.ResultSet;
import com.datastax.oss.driver.api.core.cql.Row;
// Simple query:
ResultSet rs = session.execute(
"SELECT product_id, name, price FROM products LIMIT 10");
for (Row row : rs) {
UUID productId = row.getUuid("product_id");
String name = row.getString("name");
BigDecimal price = row.getBigDecimal("price");
System.out.printf("Product: %s | %s | $%.2f%n", productId, name, price);
}
Prepared Statements (Best Practice)
Always use prepared statements for queries that run more than once. The driver prepares the statement once, sending only the CQL string to the cluster. Subsequent executions send only the bound values — faster and safer against CQL injection.
import com.datastax.oss.driver.api.core.cql.PreparedStatement;
import com.datastax.oss.driver.api.core.cql.BoundStatement;
// Prepare once (at application startup):
PreparedStatement insertProduct = session.prepare(
"INSERT INTO products (product_id, name, price, category) " +
"VALUES (?, ?, ?, ?)");
PreparedStatement selectByCategory = session.prepare(
"SELECT product_id, name, price FROM products_by_category " +
"WHERE category = ? ORDER BY price ASC LIMIT 20");
// Bind and execute for each request:
BoundStatement bound = insertProduct.bind(
UUID.randomUUID(),
"Wireless Headphones",
new BigDecimal("79.99"),
"Electronics"
);
session.execute(bound);
// Query by category:
ResultSet rs = session.execute(
selectByCategory.bind("Electronics"));
Consistency Level per Statement
import com.datastax.oss.driver.api.core.ConsistencyLevel;
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
SimpleStatement stmt = SimpleStatement
.builder("SELECT * FROM orders_by_customer WHERE customer_id = ?")
.addPositionalValue(customerId)
.setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM)
.build();
ResultSet rs = session.execute(stmt);
Asynchronous Execution
The Java driver supports non-blocking async execution using CompletionStage, which allows your application to fire many queries concurrently without blocking threads.
import java.util.concurrent.CompletionStage;
import com.datastax.oss.driver.api.core.cql.AsyncResultSet;
CompletionStage<AsyncResultSet> future = session.executeAsync(
selectByCategory.bind("Electronics"));
future.thenAccept(asyncRs -> {
for (Row row : asyncRs.currentPage()) {
System.out.println(row.getString("name"));
}
});
Paging Large Result Sets
SimpleStatement stmt = SimpleStatement
.builder("SELECT * FROM products_by_category WHERE category = 'Electronics'")
.setPageSize(50) // fetch 50 rows per page
.build();
ResultSet rs = session.execute(stmt);
int count = 0;
for (Row row : rs) {
// Driver fetches next page automatically when current page is exhausted
System.out.println(row.getString("name"));
if (++count == 150) break; // stop after 150 rows
}
Mapping to Java Objects (Object Mapper)
// Add mapper dependency:
// com.datastax.oss:java-driver-mapper-runtime:4.17.0
// com.datastax.oss:java-driver-mapper-processor:4.17.0
@Entity
@CqlName("products")
public class Product {
@PartitionKey
private UUID productId;
private String name;
private BigDecimal price;
private String category;
// getters and setters...
}
@Mapper
public interface ProductMapper {
@DaoFactory
ProductDao productDao(@DaoKeyspace String keyspace);
}
@Dao
public interface ProductDao {
@Insert
void insert(Product product);
@Select
Product findById(UUID productId);
}
// Usage:
ProductMapper mapper = new ProductMapperBuilder(session).build();
ProductDao dao = mapper.productDao("ecommerce");
Product p = new Product(UUID.randomUUID(), "USB Hub", new BigDecimal("29.99"), "Electronics");
dao.insert(p);
Product found = dao.findById(p.getProductId());
Connection Pool Configuration
import com.datastax.oss.driver.api.core.connection.ConnectionInitException;
import com.datastax.oss.driver.internal.core.pool.ChannelPool;
// In application.conf (Driver 4.x uses Typesafe Config):
datastax-java-driver {
basic.contact-points = ["10.0.0.1:9042", "10.0.0.2:9042"]
basic.local-datacenter = us-east
basic.session-keyspace = ecommerce
advanced.connection {
max-requests-per-connection = 1024
pool {
local.size = 2 # connections per local node
remote.size = 1 # connections per remote node
}
}
advanced.auth-provider {
class = PlainTextAuthProvider
username = alice
password = "Al1ce$ecure!"
}
}
// Load from config:
CqlSession session = CqlSession.builder()
.withConfigLoader(DriverConfigLoader.fromClasspath("application.conf"))
.build();
Handling Exceptions
import com.datastax.oss.driver.api.core.servererrors.*;
import com.datastax.oss.driver.api.core.*;
try {
session.execute(insertStatement);
} catch (WriteTimeoutException e) {
// Write timed out — may have partially succeeded on some replicas
System.err.println("Write timeout: " + e.getMessage());
} catch (UnavailableException e) {
// Not enough replicas available for the requested consistency
System.err.println("Unavailable: " + e.getMessage());
} catch (NoNodeAvailableException e) {
// Driver cannot reach any node
System.err.println("No node available");
}
Summary
The DataStax Java Driver connects Java applications to Cassandra through a session object that manages connection pooling, load balancing, and retries automatically. Always use prepared statements to avoid repeated parsing overhead. Set consistency levels per statement based on the query's requirements. Use async execution for concurrent workloads. Configure the driver via the application.conf file for clean, externalized settings. Handle WriteTimeoutException and UnavailableException gracefully — write timeouts in Cassandra do not always mean the write failed.
