Guide to Cassandra with Spring Boot

Apache Cassandra is a distributed database management system that is built to handle large amounts of data across multiple data centers and the cloud. This guide walks you through the process of using modules Spring Data Cassandra and Spring Boot to work with the Cassandra database (such as Astra DB).

1. Prerequisites

Before starting, make sure we have the following installed in the system.

  • Our favorite IDE
  • Maven 3.2+
  • JDK 11 or later

2. Creating a Spring Boot Application

  1. Go to https://start.spring.io.
  2. Choose Maven Project and Java.
  3. Choose the name of your project.
  4. Click on Dependencies and select Spring Data for Apache Cassandra.

After that the configuration should look like the following:

https://start.spring.io Configuration

Now, generate the project and download it to our computer. Further, we need to unzip the archive and open it with our favorite IDE. For example, we will use IntelliJ IDEA.

If we check the pom.xml file we will see the following dependency for Cassandra:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-cassandra</artifactId>
		</dependency>

3. Setting Up Cassandra Database

Before starting coding, we will need a Cassandra database to connect with. In this example, we will use the free tier of DataStax Astra Cassandra-as-a-Service. Follow the instructions in the following link to create the database and keyspace named spring_cassandra.

After that, we will need to add the astra-spring-boot-starter dependency to our pom.xml file. It helps in connecting the application with ASTRA DB.

<dependency>
    <groupId>com.datastax.astra</groupId>
    <artifactId>astra-spring-boot-starter</artifactId>
    <version>0.3.1</version>
</dependency>

4. Cassandra Configuration

Next, we should configure the database connection properties in our application.properties file. Each provider provides its specific properties so these may vary depending on the Cassandra service provider.

# Credentials to Astra DB
astra.client-id= <client-id>
astra.client-secret= <client-secret>
astra.application-token= <application-token>

# Select an Astra instance
astra.cloud-region= <region>
astra.database-id= <database-id>
astra.keyspace= spring_cassandra

#timeout configs
spring.data.cassandra.request.timeout=60s
spring.data.cassandra.connection.connect-timeout=60s
spring.data.cassandra.connection.init-query-timeout=60s

An equivalent Java configuration is given below. We can extend with AbstractCassandraConfiguration and override specific beans for setup-specific configurations.

import com.datastax.astra.boot.autoconfigure.AstraClientProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;

@Configuration
@EnableCassandraRepositories(basePackages = {"com.howtodoinjava.cassandrademo"})
public class CassandraConfig extends AstraClientProperties {

    @Override
    public String getClientId() {
        return "<Your_Client_Id>";
    }

    @Override
    public String getApplicationToken() {
        return "<Your_Application_Token>";
    }

    @Override
    public String getClientSecret() {
        return "<Your_Client_Secret>";
    }

    @Override
    public String getCloudRegion() {
        return "<Your_cloudRegion>;
    }

    @Override
    public String getDatabaseId() {
        return "<Your_database_id>";
    }

    @Override
    public String getKeyspace() {
        return "spring_cassandra";
    }
}

The spring.data.cassandra.schema-action property defines the schema action to take at startup. It can have the following values: 

  • none (recommended for production) – Take no schema actions.
  • create – Create each table as necessary.
  • create-if-not-exists – Create each table as necessary.
  • recreate – Create each table as necessary, dropping the table first if it exists.
  • recreate-drop-unused – Drop all tables in the keyspace, then create each table as necessary.

We are using create-if-not-exists to create the required schema for this demo.

The @EnableCassandraRepositories is a special Cassandra annotation that will scan the package (in our case the package that we specify in “basePackages“) for Cassandra repositories such as specified in the next section.

Additionally, we can specify the timeout settings for connections to the Cassandra database.

5. Connecting to Cassandra

5.1. Entity

We have created the Book class that works as an entity for persistence. The annotation @Table maps this entity to a Cassandra table. We are using UUID for the primary key.

@Table
public class Book {

    @PrimaryKey
    private UUID id;

    private String title;
    private String author;

// getters, setters, constructor, toString method
}

5.2. CassandraRepository Configuration

Next, we are creating a @Repository that provides the most common methods for performing basic CRUD operations in the database. Note that Spring Data Cassandra internally uses the CassandraTemplate to execute the SELECT queries. I added the addition query findBookByTitle with the annotation @AllowFiltering.

import org.springframework.data.cassandra.repository.AllowFiltering;
import org.springframework.data.cassandra.repository.CassandraRepository;
import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;

public interface BookRepository extends CassandraRepository<Book, Long> {

    @AllowFiltering
    Book findBookByTitle(String title);
}

6. Accessing Data with CassandraRepository

It’s time to test the connection. We are using CommandLineRunner which executes the given code after the application is started. We will insert some books into the database. Then we will select one book and update it. After that, we will delete one, and we will select all the books from the database.

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import java.util.Arrays;

@SpringBootApplication
public class AccessingDataCassandraApplication {

	public static void main(String[] args) {
		SpringApplication.run(AccessingDataCassandraApplication.class, args);
	}

	@Bean
	public CommandLineRunner clr(BookRepository bookRepository) {
		return args -> {

			// save books in the database
			bookRepository.saveAll(Arrays.asList(
					new Book(1L,"War and Peace", "Tolstoy"),
					new Book(2L,"Harry Potter", "Rowling, J.K."),
					new Book(3L,"Anna Karenina", "Tolstoy")
			));

			// select only on book
			Book harryPotter = bookRepository.findBookByTitle("Harry Potter");

			// modify the selected book
			harryPotter.setTitle("Harry Potter and the Philosopher's Stone");
			bookRepository.save(harryPotter);

			//delete the book with id 1
			bookRepository.deleteById(1L);

			//get all the books
			bookRepository.findAll().forEach(System.out::println);
		};
	}
}

The output in the console is:

7. Enable Filtering

If you are searching for non-equivalence, Cassandra has to do a full table scan. So instead of performing the above action, Cassandra fails the request with a warning. Here, we need to annotate and mark the interface method with @AllowFiltering to ping Spring Data Cassandra to send it with the filter query and allow the database to perform it.

To understand better the role of the @AllowFiltering annotation let’s try to run the code without it. If you do so you will get the following error:

With the message: Cannot execute this query as it might involve data filtering and thus may have unpredictable performance. If you want to execute this query despite the performance unpredictability, use ALLOW FILTERING

With this message, Cassandra tells us that we want to execute a query with an unpredictable result that may have performance issues.

Use of ALLOW FILTERING is not recommended unless you are confident the table contains a very small set of data in it. Using it on large data can have performance issues.

8. Conclusion

It’s not hard at all to start playing with Cassandra in your personal projects right now. Cassandra is very useful and a very good skill to learn and perfect for your career as a developer.

Happy Learning !!

Source Code on Github

Leave a Reply

0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions, and frequently asked interview questions.