Java 8, 11, 17+
Java Driver
Build high-performance enterprise Java apps with Cassandra!
📦 Maven Setup & Dependencies
Add driver to your project!
1
Maven pom.xml
Add dependency to your project
<!-- Add to pom.xml -->
<dependencies>
<!-- Cassandra Java Driver 4.x -->
<dependency>
<groupId>com.datastax.oss</groupId>
<artifactId>java-driver-core</artifactId>
<version>4.18.0</version>
</dependency>
<!-- Object Mapper (optional) -->
<dependency>
<groupId>com.datastax.oss</groupId>
<artifactId>java-driver-mapper-runtime</artifactId>
<version>4.18.0</version>
</dependency>
</dependencies>
2
Gradle build.gradle
For Gradle projects
// Add to build.gradle
dependencies {
// Cassandra Java Driver
implementation 'com.datastax.oss:java-driver-core:4.18.0'
// Object Mapper (optional)
implementation 'com.datastax.oss:java-driver-mapper-runtime:4.18.0'
annotationProcessor 'com.datastax.oss:java-driver-mapper-processor:4.18.0'
}
System Requirements
| Component | Requirement | Notes |
|---|---|---|
| Java | 8, 11, 17+ | LTS versions recommended |
| Driver | 4.18.0+ | Latest stable version |
| Cassandra | 2.1+ | Best with 3.11 or 4.0+ |
| Build Tool | Maven 3.6+ or Gradle 7+ | For dependency management |
🚀 Quick Start Example
Your first Java + Cassandra app!
// HelloCassandra.java
import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.cql.*;
import java.net.InetSocketAddress;
import java.util.UUID;
public class HelloCassandra {
public static void main(String[] args) {
// 1. Connect to Cassandra
try (CqlSession session = CqlSession.builder()
.addContactPoint(new InetSocketAddress("127.0.0.1", 9042))
.withLocalDatacenter("datacenter1")
.build()) {
// 2. Create keyspace
session.execute("""
CREATE KEYSPACE IF NOT EXISTS tutorial
WITH replication = {
'class': 'SimpleStrategy',
'replication_factor': 1
}
""");
// 3. Create table
session.execute("""
CREATE TABLE IF NOT EXISTS tutorial.users (
user_id UUID PRIMARY KEY,
name TEXT,
email TEXT,
age INT
)
""");
// 4. Insert data
UUID userId = UUID.randomUUID();
PreparedStatement insertStmt = session.prepare(
"INSERT INTO tutorial.users (user_id, name, email, age) VALUES (?, ?, ?, ?)"
);
session.execute(insertStmt.bind(userId, "Alice", "alice@example.com", 28));
// 5. Query data
ResultSet results = session.execute("SELECT * FROM tutorial.users");
for (Row row : results) {
System.out.printf("%s (%s) - Age: %d%n",
row.getString("name"),
row.getString("email"),
row.getInt("age")
);
}
}
// Session auto-closed by try-with-resources
}
}
// Output: Alice (alice@example.com) - Age: 28
Compile and Run
# Compile
$ mvn compile
# Run
$ mvn exec:java -Dexec.mainClass="HelloCassandra"
# Output:
Alice (alice@example.com) - Age: 28
🔌 Connection Management
Proper session setup!
Basic Connection
import com.datastax.oss.driver.api.core.CqlSession;
import java.net.InetSocketAddress;
// Simple connection
CqlSession session = CqlSession.builder()
.addContactPoint(new InetSocketAddress("127.0.0.1", 9042))
.withLocalDatacenter("datacenter1")
.withKeyspace("my_keyspace")
.build();
// Use session...
// Always close when done
session.close();
Production-Ready Connection
import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.CqlSessionBuilder;
import com.datastax.oss.driver.api.core.config.*;
import java.net.InetSocketAddress;
import java.time.Duration;
public class CassandraConnection {
public static CqlSession createSession() {
return CqlSession.builder()
// Contact points
.addContactPoint(new InetSocketAddress("node1", 9042))
.addContactPoint(new InetSocketAddress("node2", 9042))
.addContactPoint(new InetSocketAddress("node3", 9042))
// Datacenter
.withLocalDatacenter("datacenter1")
// Authentication
.withAuthCredentials("cassandra", "cassandra")
// Keyspace
.withKeyspace("my_keyspace")
// Timeouts
.withConfigLoader(DriverConfigLoader.programmaticBuilder()
.withDuration(DefaultDriverOption.REQUEST_TIMEOUT,
Duration.ofSeconds(10))
.withDuration(DefaultDriverOption.CONNECTION_INIT_QUERY_TIMEOUT,
Duration.ofSeconds(5))
.build())
.build();
}
}
Singleton Pattern (Recommended)
// CassandraManager.java
import com.datastax.oss.driver.api.core.CqlSession;
import java.net.InetSocketAddress;
public class CassandraManager {
private static CqlSession session;
private CassandraManager() {}
public static synchronized CqlSession getSession() {
if (session == null) {
session = CqlSession.builder()
.addContactPoint(new InetSocketAddress("localhost", 9042))
.withLocalDatacenter("datacenter1")
.withKeyspace("my_keyspace")
.build();
}
return session;
}
public static void shutdown() {
if (session != null) {
session.close();
session = null;
}
}
}
// Usage in your app
public class UserService {
public User getUser(UUID userId) {
CqlSession session = CassandraManager.getSession();
// Execute queries...
return user;
}
}
// On application shutdown
CassandraManager.shutdown();
📝 Basic Query Operations
CRUD operations!
SELECT Queries
import com.datastax.oss.driver.api.core.cql.*;
// Simple select
ResultSet results = session.execute(
"SELECT * FROM users"
);
for (Row row : results) {
System.out.println(row.getString("name") + ": " +
row.getString("email"));
}
// With parameters
SimpleStatement stmt = SimpleStatement.newInstance(
"SELECT * FROM users WHERE user_id = ?",
userId
);
ResultSet rs = session.execute(stmt);
// Get single row
Row row = rs.one();
if (row != null) {
String name = row.getString("name");
Integer age = row.getInt("age");
}
INSERT Queries
import java.util.UUID;
// Simple insert
session.execute(SimpleStatement.newInstance(
"INSERT INTO users (user_id, name, email, age) VALUES (?, ?, ?, ?)",
UUID.randomUUID(),
"Bob",
"bob@example.com",
30
));
// Insert with TTL
session.execute(SimpleStatement.newInstance(
"INSERT INTO sessions (session_id, user_id) VALUES (?, ?) USING TTL ?",
sessionId,
userId,
3600 // 1 hour
));
// Conditional insert
ResultSet result = session.execute(SimpleStatement.newInstance(
"INSERT INTO users (user_id, name, email) VALUES (?, ?, ?) IF NOT EXISTS",
userId,
"Charlie",
"charlie@example.com"
));
if (result.wasApplied()) {
System.out.println("User created");
} else {
System.out.println("User already exists");
}
UPDATE Queries
// Simple update
session.execute(SimpleStatement.newInstance(
"UPDATE users SET age = ?, email = ? WHERE user_id = ?",
31,
"newemail@example.com",
userId
));
// Conditional update
ResultSet result = session.execute(SimpleStatement.newInstance(
"UPDATE users SET age = ? WHERE user_id = ? IF age = ?",
32,
userId,
31
));
if (result.wasApplied()) {
System.out.println("Update successful");
}
// Increment counter
session.execute(SimpleStatement.newInstance(
"UPDATE page_views SET views = views + ? WHERE page_id = ?",
1,
pageId
));
DELETE Queries
// Delete row
session.execute(SimpleStatement.newInstance(
"DELETE FROM users WHERE user_id = ?",
userId
));
// Delete specific columns
session.execute(SimpleStatement.newInstance(
"DELETE email, age FROM users WHERE user_id = ?",
userId
));
// Conditional delete
ResultSet result = session.execute(SimpleStatement.newInstance(
"DELETE FROM users WHERE user_id = ? IF age > ?",
userId,
50
));
if (result.wasApplied()) {
System.out.println("User deleted");
}
BATCH Queries
import com.datastax.oss.driver.api.core.cql.BatchStatement;
import com.datastax.oss.driver.api.core.cql.DefaultBatchType;
// Create batch statement
BatchStatement batch = BatchStatement.newInstance(
DefaultBatchType.LOGGED,
SimpleStatement.newInstance(
"INSERT INTO users (user_id, name) VALUES (?, ?)",
UUID.randomUUID(), "User1"
),
SimpleStatement.newInstance(
"INSERT INTO users (user_id, name) VALUES (?, ?)",
UUID.randomUUID(), "User2"
),
SimpleStatement.newInstance(
"INSERT INTO users (user_id, name) VALUES (?, ?)",
UUID.randomUUID(), "User3"
)
);
// Execute batch (atomic)
session.execute(batch);
// WARNING: Only batch operations on SAME partition!
⚡ Prepared Statements
Maximum performance!
Why Use Prepared Statements?
- ✅ Performance: 10x faster execution (parsed once)
- ✅ Security: Protection from CQL injection
- ✅ Type safety: Compile-time parameter validation
- ✅ Efficiency: Less network overhead
Basic Prepared Statements
import com.datastax.oss.driver.api.core.cql.*;
// Prepare statement ONCE (at startup)
PreparedStatement insertUser = session.prepare(
"INSERT INTO users (user_id, name, email, age) VALUES (?, ?, ?, ?)"
);
// Execute MANY times (in request handlers)
session.execute(insertUser.bind(
UUID.randomUUID(), "Alice", "alice@example.com", 28
));
session.execute(insertUser.bind(
UUID.randomUUID(), "Bob", "bob@example.com", 30
));
session.execute(insertUser.bind(
UUID.randomUUID(), "Charlie", "charlie@example.com", 25
));
// 10x faster than SimpleStatement! ✅
Named Parameters
// Prepare with named parameters
PreparedStatement selectUser = session.prepare(
"SELECT name, email, age FROM users WHERE user_id = :userId AND age > :minAge"
);
// Bind by name
BoundStatement bound = selectUser.bind()
.setUuid("userId", userId)
.setInt("minAge", 25);
ResultSet results = session.execute(bound);
Query Repository Pattern
// UserRepository.java
import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.cql.*;
import java.util.UUID;
public class UserRepository {
private final CqlSession session;
private final PreparedStatement insertStmt;
private final PreparedStatement selectStmt;
private final PreparedStatement updateStmt;
private final PreparedStatement deleteStmt;
public UserRepository(CqlSession session) {
this.session = session;
// Prepare all statements at startup
this.insertStmt = session.prepare(
"INSERT INTO users (user_id, name, email, age) VALUES (?, ?, ?, ?)"
);
this.selectStmt = session.prepare(
"SELECT * FROM users WHERE user_id = ?"
);
this.updateStmt = session.prepare(
"UPDATE users SET name = ?, email = ?, age = ? WHERE user_id = ?"
);
this.deleteStmt = session.prepare(
"DELETE FROM users WHERE user_id = ?"
);
}
public void createUser(UUID userId, String name, String email, int age) {
session.execute(insertStmt.bind(userId, name, email, age));
}
public Row findUser(UUID userId) {
ResultSet rs = session.execute(selectStmt.bind(userId));
return rs.one();
}
public void updateUser(UUID userId, String name, String email, int age) {
session.execute(updateStmt.bind(name, email, age, userId));
}
public void deleteUser(UUID userId) {
session.execute(deleteStmt.bind(userId));
}
}
// Usage
UserRepository repo = new UserRepository(session);
repo.createUser(UUID.randomUUID(), "Alice", "alice@example.com", 28);
🔄 Reactive API
Non-blocking reactive queries!
Reactive Programming
Java driver 4.x supports full reactive programming with Project Reactor!
- ✅ Non-blocking async operations
- ✅ Backpressure handling
- ✅ Streaming large result sets
- ✅ Composable operations
Reactive Query Execution
import com.datastax.oss.driver.api.core.cql.AsyncResultSet;
import java.util.concurrent.CompletionStage;
// Async query returns CompletionStage
CompletionStage<AsyncResultSet> future =
session.executeAsync("SELECT * FROM users WHERE user_id = ?", userId);
// Handle result asynchronously
future.thenAccept(resultSet -> {
for (Row row : resultSet.currentPage()) {
System.out.println(row.getString("name"));
}
}).exceptionally(error -> {
System.err.println("Query failed: " + error.getMessage());
return null;
});
Reactive Streams
import com.datastax.dse.driver.api.core.cql.reactive.ReactiveResultSet;
import reactor.core.publisher.Flux;
// Execute query reactively
ReactiveResultSet reactiveRs = session.executeReactive("SELECT * FROM users");
// Convert to Flux (reactive stream)
Flux.from(reactiveRs)
.map(row -> row.getString("name"))
.doOnNext(System.out::println)
.doOnError(error -> System.err.println("Error: " + error))
.doOnComplete(() -> System.out.println("Query complete"))
.subscribe();
🗺️ Object Mapping
Map POJOs to tables!
Object Mapper
The Java driver includes a powerful object mapper that automatically maps Java objects to Cassandra tables!
- ✅ Automatic CRUD operations
- ✅ Type-safe queries
- ✅ Compile-time code generation
- ✅ No reflection at runtime
Entity Definition
import com.datastax.oss.driver.api.mapper.annotations.*;
import java.util.UUID;
@Entity
@CqlName("users")
public class User {
@PartitionKey
private UUID userId;
private String name;
private String email;
private Integer age;
// Constructors
public User() {}
public User(UUID userId, String name, String email, Integer age) {
this.userId = userId;
this.name = name;
this.email = email;
this.age = age;
}
// Getters and setters
public UUID getUserId() { return userId; }
public void setUserId(UUID userId) { this.userId = userId; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
}
DAO Interface
import com.datastax.oss.driver.api.mapper.annotations.*;
import java.util.UUID;
@Dao
public interface UserDao {
@Insert
void save(User user);
@Select
User findById(UUID userId);
@Update
void update(User user);
@Delete
void delete(User user);
@Query("SELECT * FROM users WHERE age > :age")
PagingIterable<User> findByAgeGreaterThan(int age);
}
Mapper Interface
import com.datastax.oss.driver.api.mapper.annotations.*;
@Mapper
public interface UserMapper {
@DaoFactory
UserDao userDao(@DaoKeyspace CqlIdentifier keyspace);
}
Usage
import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.mapper.MapperBuilder;
import java.util.UUID;
// Create mapper (once at startup)
UserMapper mapper = new UserMapperBuilder(session).build();
UserDao userDao = mapper.userDao(CqlIdentifier.fromCql("my_keyspace"));
// Create user
User user = new User(
UUID.randomUUID(),
"Alice",
"alice@example.com",
28
);
userDao.save(user);
// Find user
User found = userDao.findById(user.getUserId());
System.out.println(found.getName());
// Update user
found.setAge(29);
userDao.update(found);
// Custom query
for (User u : userDao.findByAgeGreaterThan(25)) {
System.out.println(u.getName());
}
// Delete user
userDao.delete(found);
💡 Java Driver Best Practices
Production tips!
DO
- Use singleton pattern for CqlSession
- Use prepared statements for repeated queries
- Use object mapper for clean code
- Use try-with-resources for auto-close
- Configure appropriate timeouts
- Use async/reactive for high throughput
- Monitor session metrics
- Close session on shutdown
DON'T
- Create session per request
- Use string concatenation for queries
- Ignore timeout configuration
- Use blocking calls in reactive code
- Forget to close sessions
- Mix sync and async patterns
- Skip connection pooling config
- Use SELECT * on large tables
Performance Tips
| Technique | Benefit | When to Use |
|---|---|---|
| Prepared Statements | 10x faster | Repeated queries |
| Async/Reactive | Non-blocking | High concurrency |
| Object Mapper | Type-safe, clean code | CRUD-heavy apps |
| Batch Statements | Atomic operations | Same partition updates |
| Connection Pooling | Resource efficiency | Always (automatic) |
Complete Production Example
// Application.java - Production-ready
import com.datastax.oss.driver.api.core.CqlSession;
import java.net.InetSocketAddress;
public class Application {
private static CqlSession session;
private static UserRepository userRepository;
public static void main(String[] args) {
// Initialize at startup
initialize();
try {
// Your application logic
runApplication();
} finally {
// Clean shutdown
shutdown();
}
}
private static void initialize() {
// Create session (ONCE)
session = CqlSession.builder()
.addContactPoint(new InetSocketAddress("localhost", 9042))
.withLocalDatacenter("datacenter1")
.withKeyspace("my_keyspace")
.build();
// Initialize repository with prepared statements
userRepository = new UserRepository(session);
}
private static void runApplication() {
// Use repository in your handlers
UUID userId = UUID.randomUUID();
userRepository.createUser(userId, "Alice", "alice@example.com", 28);
Row user = userRepository.findUser(userId);
System.out.println(user.getString("name"));
}
private static void shutdown() {
if (session != null) {
session.close();
}
}
}
🎉 Master Java + Cassandra!
You now know how to build enterprise Java apps with Cassandra!
🎓 What You Learned:
- 📦 Maven setup: com.datastax.oss:java-driver-core:4.18.0
- 🚀 Quick start: Complete example with CqlSession
- 🔌 Connection: Singleton pattern, production config
- 📝 Basic queries: SELECT, INSERT, UPDATE, DELETE, BATCH
- ⚡ Prepared statements: 10x faster, repository pattern
- 🔄 Reactive API: Non-blocking with CompletionStage
- 🗺️ Object mapping: Type-safe POJO to table mapping
- 💡 Best practices: Production-ready patterns
💡 Key Takeaways:
- Singleton CqlSession - Create once, reuse everywhere
- Prepared statements - 10x faster for repeated queries
- Object mapper - Type-safe, annotation-based mapping
- Reactive API - Non-blocking with CompletionStage/Flux
- Try-with-resources - Automatic session cleanup
- Repository pattern - Organize prepared statements
☕ Quick Reference:
// Maven dependency
com.datastax.oss:java-driver-core:4.18.0
// Connect (singleton)
CqlSession session = CqlSession.builder()
.addContactPoint(new InetSocketAddress("localhost", 9042))
.withLocalDatacenter("datacenter1")
.build();
// Prepared statement (10x faster!)
PreparedStatement ps = session.prepare("SELECT * FROM users WHERE id = ?");
session.execute(ps.bind(userId));
// Async query
CompletionStage<AsyncResultSet> future = session.executeAsync(...);
// Close
session.close();
☕ Java + Cassandra = Enterprise power! 🎯
Start building now!
Advertisement
📱 Responsive Ad 📱