Cassandra with Spring Boot
Spring Boot's Spring Data Cassandra module provides seamless integration between Spring Boot applications and Apache Cassandra. It offers repository pattern support, automatic CQL generation, and object-to-table mapping through annotations — allowing you to work with Cassandra using familiar Spring patterns.
Adding Dependencies
Maven
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-cassandra</artifactId> </dependency>
Gradle
implementation 'org.springframework.boot:spring-boot-starter-data-cassandra'
Configuration (application.yml)
spring:
cassandra:
contact-points: 10.0.0.1,10.0.0.2
port: 9042
local-datacenter: us-east
keyspace-name: ecommerce
username: alice
password: Al1ce$ecure!
schema-action: NONE # use CREATE_IF_NOT_EXISTS for dev
request:
consistency: LOCAL_QUORUM
timeout: 10s
connection:
connect-timeout: 10s
init-query-timeout: 10s
Defining an Entity (Table Mapping)
import org.springframework.data.cassandra.core.mapping.*;
import org.springframework.data.annotation.Id;
import java.math.BigDecimal;
import java.util.UUID;
@Table("products")
public class Product {
@PrimaryKey
private UUID productId;
@Column("name")
private String name;
@Column("price")
private BigDecimal price;
@Column("category")
private String category;
// Constructors, getters, setters...
public Product(UUID productId, String name, BigDecimal price, String category) {
this.productId = productId;
this.name = name;
this.price = price;
this.category = category;
}
// getters and setters omitted for brevity
}
Composite Primary Key Entity
@PrimaryKeyClass
public class OrderKey implements Serializable {
@PrimaryKeyColumn(name = "customer_id", ordinal = 0,
type = PrimaryKeyType.PARTITIONED)
private UUID customerId;
@PrimaryKeyColumn(name = "order_date", ordinal = 1,
type = PrimaryKeyType.CLUSTERED,
ordering = Ordering.DESCENDING)
private Instant orderDate;
@PrimaryKeyColumn(name = "order_id", ordinal = 2,
type = PrimaryKeyType.CLUSTERED)
private UUID orderId;
// constructors, getters, setters, equals, hashCode...
}
@Table("orders_by_customer")
public class Order {
@PrimaryKey
private OrderKey key;
private String status;
private BigDecimal total;
// getters and setters...
}
Creating a Repository
import org.springframework.data.cassandra.repository.CassandraRepository;
import org.springframework.data.cassandra.repository.Query;
import java.util.List;
import java.util.UUID;
public interface ProductRepository extends CassandraRepository<Product, UUID> {
// Spring Data generates the CQL automatically:
List<Product> findByCategory(String category);
// Custom query:
@Query("SELECT * FROM products WHERE product_id = ?0")
Product findProductById(UUID productId);
}
Using the Repository in a Service
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import java.util.UUID;
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
public Product createProduct(String name, BigDecimal price, String category) {
Product product = new Product(UUID.randomUUID(), name, price, category);
return productRepository.save(product);
}
public Product getProduct(UUID productId) {
return productRepository.findById(productId).orElse(null);
}
public List<Product> getByCategory(String category) {
return productRepository.findByCategory(category);
}
public void deleteProduct(UUID productId) {
productRepository.deleteById(productId);
}
}
Using CassandraTemplate for Advanced Queries
import org.springframework.data.cassandra.core.CassandraTemplate;
import org.springframework.data.cassandra.core.query.Query;
import org.springframework.data.cassandra.core.query.Criteria;
@Service
public class OrderService {
@Autowired
private CassandraTemplate cassandraTemplate;
public List<Order> getRecentOrders(UUID customerId) {
Query query = Query.query(
Criteria.where("customer_id").is(customerId)
).limit(20);
return cassandraTemplate.select(query, Order.class);
}
public void updateOrderStatus(OrderKey key, String newStatus) {
cassandraTemplate.update(
Query.query(Criteria.where("customer_id").is(key.getCustomerId())
.and("order_date").is(key.getOrderDate())
.and("order_id").is(key.getOrderId())),
org.springframework.data.cassandra.core.query.Update.empty()
.set("status", newStatus),
Order.class
);
}
}
REST Controller Example
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.UUID;
@RestController
@RequestMapping("/api/products")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping("/{id}")
public Product getProduct(@PathVariable UUID id) {
return productService.getProduct(id);
}
@GetMapping("/category/{category}")
public List<Product> getByCategory(@PathVariable String category) {
return productService.getByCategory(category);
}
@PostMapping
public Product createProduct(@RequestBody ProductRequest req) {
return productService.createProduct(
req.getName(), req.getPrice(), req.getCategory());
}
@DeleteMapping("/{id}")
public void deleteProduct(@PathVariable UUID id) {
productService.deleteProduct(id);
}
}
Schema Creation Options
schema-action value Behavior ────────────────────────────────────────────────────────────── NONE Do not touch schema (use in production) CREATE_IF_NOT_EXISTS Create tables if they do not exist (dev) RECREATE Drop and recreate tables on startup (dev) RECREATE_DROP_UNUSED Recreate + remove tables not in model (dev)
Summary
Spring Data Cassandra integrates Cassandra into Spring Boot applications using familiar repository patterns and JPA-like annotations. Define entities with @Table and @PrimaryKey annotations, create repository interfaces by extending CassandraRepository, and inject them into services. Use CassandraTemplate for complex queries that repositories cannot express. Set schema-action: NONE in production and use migration scripts to control schema changes. Configure consistency levels per-request in application.yml or at the CassandraTemplate level for fine-grained control.
