Spring Data Cassandra Example
In the previous example, we demonstrated the configuration of Spring Data with GemFire, an in-memory NoSQL Database. So continuing on the same series, in this example we shall demonstrate how to connect Spring Data Application to Apache Cassandra, a Column based NoSql Database.
Cassandra is a Distributed Database Management System that can handle large amounts of data with data replication across multiple data-centres so that there is no single point of failure. It uses CQL
as its query language which has syntax quite similar to its homonym SQL
.
As Cassandra is a new technology, it has its own set of challenges and learning curve. To help with this, Spring Data
hides the complexity of writing queries and other configuration stuff. Spring Data Cassandra offers the users a familiar interface to those who have used Spring Data in the past.
1. Implementation
We need to install Cassandra Database Server, first. For Windows System, Cassandra can be downloaded from plannetcassandra and for Linux System it can be downloaded from the Apache Mirrors.
Once Cassandra is up and running, we need to create a key-space which corresponds to the schema in the RDBMS
world. We then create a column family in cassandra which can be colloquially referred to a RDMBS
Table.
Then, we need to have following JAR Files to connect to Cassandra Server:
- aopalliancejar
- cassandra-driver-core.jar
- commons-logging.jar
- guava.jar
- metrics-core.jar
- slf4j-api.jar
- spring-aop-RELEASE.jar
- spring-beans-RELEASE.jar
- spring-context-RELEASE.jar
- spring-core-RELEASE.jar
- spring-cql-RELEASE.jar
- spring-data-cassandra-RELEASE.jar
- spring-data-commons-RELEASE.jar
- spring-expression-RELEASE.jar
- spring-tx-RELEASE.jar
Create a project in eclipse or any IDE and add the JAR files downloaded above. Now that the project is setup, we start with the coding phase :
We create a PoJo which maps the Column family and is the basic unit that is to be persisted in the Cassandra Database.
Person.java
package com.jcg.examples.entity; import org.springframework.data.cassandra.mapping.PrimaryKey; import org.springframework.data.cassandra.mapping.Table; @Table("Person") public class Person { @PrimaryKey private Integer pId; private String name; public Integer getpId() { return pId; } public void setpId(Integer pId) { this.pId = pId; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Person [pId=" + pId + ", name=" + name + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((pId == null) ? 0 : pId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (pId == null) { if (other.pId != null) return false; } else if (!pId.equals(other.pId)) return false; return true; } }
We annotate the class with @Table
annotation to mark it as PoJo which is being mapped and the column-family
name to which it should correspond in the Key-Space. @PrimaryKey
simply marks the property as the Primary key.
Now that the PoJo is ready we need to create the DAO layer. The PersonRepo
interface does the job of this.
PersonRepo.java
package com.jcg.examples.repo; import org.springframework.data.repository.CrudRepository; import com.jcg.examples.entity.Person; public interface PersonRepo extends CrudRepository<Person, String> { @Query("Select * from person where pid=?0") public Person fetchByPId(int pid); }
The Spring Data provides a number of inbuilt method for manipulating the Data. We need not write the queries for basic data manipulation and reading. It is achieved by extending the CrudRepository
and declaring the proper Generics as per the PoJo, which in our case is the Person, String
. In case the Developer is not satisfied with the existing method, he can create his own method by specifying the Query using the @Query
annotation.
The Spring IoC Container creates an instance of this Repository
and makes it available to be used as a Bean
.
The last and the most important part is to configure the Spring Container
using the spring-config.xml
:
Spring-config.xml
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans" xmlns:cassandra="http://www.springframework.org/schema/data/cassandra" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/cql http://www.springframework.org/schema/cql/spring-cql-1.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/cassandra http://www.springframework.org/schema/data/cassandra/spring-cassandra.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <cassandra:cluster id="cassandraCluster" contact-points="127.0.0.1" port="9042" /> <cassandra:converter /> <cassandra:session id="cassandraSession" cluster-ref="cassandraCluster" keyspace-name="jcg" /> <cassandra:template id="cqlTemplate" /> <cassandra:repositories base-package="com.jcg.examples.repo" /> <cassandra:mapping entity-base-packages="com.jcg.examples.entity" /> </beans:beans>
- Line 11 :
- Line 14 :
- Line 17 :
- Line 20 :
- Line 22 :
Configuring the Cassandra cluster. The default port in 9042.
Cassandra Session can be colloquially referred to as a Sort of connection pool to connect to the cluster. We configure the cassandra session for the key-space "jcg"
.
Cassandra Template can be used to execute queries. But in this example we are creating only because it is dependency to create the Cassandra Repositories for the PoJos.
Scan the packages for initializing Cassandra Repositories.
Declare Mapping for the PoJos.
Now that all is set, let’s run the application and test out the code! Here’s Application class that loads the XML file to instantiate the Spring Container and execute a few queries.
Application.java
package com.jcg.examples.test; import java.util.List; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.io.ClassPathResource; import com.jcg.examples.entity.Person; import com.jcg.examples.repo.PersonRepo; public class Application { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new ClassPathResource("resources/spring-config.xml").getPath()); PersonRepo personRepo = context.getBean(PersonRepo.class); Person personAchilles = new Person(); personAchilles.setpId(1); personAchilles.setName("Achilles"); personRepo.save(personAchilles); Person personHektor = new Person(); personHektor.setpId(2); personHektor.setName("Hektor"); personRepo.save(personHektor); Iterable<Person> personList = personRepo.findAll(); System.out.println("Person List : "); for (Person person : personList) { System.out.println(person); } System.out.println("Person with Id 1 is "+personRepo.fetchByPId(1)); context.close(); } }
In the Application class we created two instances of Person class and persisted them to the Cassandra Database. We then fetch all the records in the Person Column family and print them on the screen. Then we executed a query via the personRepo
object to fetch the instance by specifying the Primary Key.
Here’s the sample output of the program :
Aug 02, 2015 2:56:27 AM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@78221c75: startup date [Sun Aug 02 02:56:27 IST 2015]; root of context hierarchy Aug 02, 2015 2:56:27 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [resources/spring-config.xml] SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. Person List : Person [pId=1, name=Achilles] Person [pId=2, name=Hektor] Person with Id 1 is Person [pId=1, name=Achilles] Aug 02, 2015 2:56:28 AM org.springframework.context.support.ClassPathXmlApplicationContext doClose INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@78221c75: startup date [Sun Aug 02 02:56:27 IST 2015]; root of context hierarchy
2. Download the Source Code
Here we demonstrated how to configure and manage a Cassandra Data Repository using Spring Data.
You can download the source code of this example here: CassandraSpringData.zip