Wednesday, August 19, 2015

Spring Data Cassandra - CRUD Operations

Hi, in this post we are going to see how to connect with Cassandra NoSQL database using Spring data.

Project Structure:
Tools and Technologies:
  • Java 8
  • Spring 3.2.8
  • Cassandra 2.1.8
  • Spring-Data-Cassandra 1.0.0
  • Maven 3.0.4
Cassandra Keyspace and Table Creation:
cqlsh> create keyspace "ranga" with replication = {'class': 'SimpleStrategy', 'replication_factor': '1'};

cqlsh> CREATE TABLE employee(id int, name text, salary float, PRIMARY KEY(id));
Maven Configuration file:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.samples</groupId>
<artifactId>CassandraCRUDOperations</artifactId>
<version>1.0.0-SNAPSHOT</version>

<properties>

<!-- Java Version -->
<java.version>1.8</java.version>

<!-- Spring -->
<spring-framework.version>3.2.8.RELEASE</spring-framework.version>
<!-- 4.2.0.RELEASE -->

<!-- Cassandra -->
<cassandra.version>1.0.0.RELEASE</cassandra.version>

<!-- Logging -->
<logback.version>1.0.13</logback.version>
<slf4j.version>1.7.5</slf4j.version>

<!-- Test -->
<junit.version>4.11</junit.version>

</properties>

<dependencies>

<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-framework.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-framework.version}</version>
</dependency>

<!-- Spring Data Cassandra -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra</artifactId>
<version>${cassandra.version}</version>
</dependency>

<!-- Spring Test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-framework.version}</version>
<scope>test</scope>
</dependency>

<!-- Logging with SLF4J & LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>

</project>

Cassandra database properties file:
src/main/resources/cassandra.properties
cassandra.contactpoints=localhost,127.0.0.1
cassandra.port=9042
cassandra.keyspace=ranga
Cassandra Template configuration file:
com/ranga/util/CassandraUtil.java
package com.ranga.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.cassandra.config.CassandraClusterFactoryBean;
import org.springframework.data.cassandra.config.CassandraSessionFactoryBean;
import org.springframework.data.cassandra.config.SchemaAction;
import org.springframework.data.cassandra.convert.CassandraConverter;
import org.springframework.data.cassandra.convert.MappingCassandraConverter;
import org.springframework.data.cassandra.core.CassandraOperations;
import org.springframework.data.cassandra.core.CassandraTemplate;
import org.springframework.data.cassandra.mapping.BasicCassandraMappingContext;
import org.springframework.data.cassandra.mapping.CassandraMappingContext;

/**
* Utility class for getting the CassandraOperations object.
* @author Ranga Reddy
* @version 1.0
*/


@Configuration
@PropertySource(value = { "classpath:cassandra.properties" })
public class CassandraUtil {

/**
* Constant String for Keyspace
*/

private static final String KEYSPACE = "cassandra.keyspace";
/**
* Constant String for ContactPoints
*/

private static final String CONTACTPOINTS = "cassandra.contactpoints";
/**
* Constant String for Port
*/

private static final String PORT = "cassandra.port";

@Autowired
private Environment environment;

public CassandraUtil() {
System.out.println("CassandraUtil()");
}

private String getKeyspaceName() {
return environment.getProperty(KEYSPACE);
}

private String getContactPoints() {
return environment
.getProperty(CONTACTPOINTS);
}

private int getPortNumber() {
return Integer.parseInt(environment
.getProperty(PORT));
}

@Bean
public CassandraClusterFactoryBean cluster() {
CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
cluster.setContactPoints(getContactPoints());
cluster.setPort(getPortNumber());
return cluster;
}

@Bean
public CassandraMappingContext mappingContext() {
return new BasicCassandraMappingContext();
}

@Bean
public CassandraConverter converter() {
return new MappingCassandraConverter(mappingContext());
}

@Bean
public CassandraSessionFactoryBean session() throws Exception {
CassandraSessionFactoryBean cassandraSessionFactoryBean = new CassandraSessionFactoryBean();
cassandraSessionFactoryBean.setCluster(cluster().getObject());
cassandraSessionFactoryBean.setKeyspaceName(getKeyspaceName());
cassandraSessionFactoryBean.setConverter(converter());
cassandraSessionFactoryBean.setSchemaAction(SchemaAction.NONE);
return cassandraSessionFactoryBean;
}

@Bean
public CassandraOperations cassandraTemplate() throws Exception {
return new CassandraTemplate(session().getObject());
}
}

com/ranga/util/MyCassandraTemplate.java
package com.ranga.util;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.cassandra.core.CassandraOperations;

/**
* Utility class for handling all CRUD Operations.
* @author Ranga Reddy
* @version 1.0
*/

public class MyCassandraTemplate {

@Autowired
private CassandraOperations cassandraTemplate;

/**
* Creating the entity.
* @param entity
* @return {@link Object}
*/

public <T> T create(T entity) {
return cassandraTemplate.insert(entity);
}

/**
* Creating the entity.
* @param entity
* @param claz
* @return T
*/

public <T> T create(T entity, Class<T> claz) {
return (T) cassandraTemplate.insert(entity);
}

/**
* Creating the list of entities.
* @param entity
*/

public <T> void createList(List<T> entities) {
cassandraTemplate.insert(entities);
}

/**
* Updating the entity.
* @param entity
* @param claz
* @return T
*/

public <T> T update(T entity) {
return (T) cassandraTemplate.update(entity);
}

/**
* Updating the list of entities.
* @param entity
* @param claz
* @return T
*/

public <T> void updateList(List<T> entities) {
cassandraTemplate.update(entities);
}

/**
* Updating the entity.
* @param entity
* @param claz
* @return T
*/

public <T> T update(T entity, Class<T> claz) {
return (T) cassandraTemplate.update(entity);
}

/**
* Get the Entity using Id.
* @param id
* @param claz
* @return T
*/

public <T> T findById(Object id, Class<T> claz) {
return cassandraTemplate.selectOneById(claz, id);
}

/**
* Delete the Entity using Id.
* @param id
* @param claz
*/

public <T> void deleteById(Object id, Class<T> claz) {
cassandraTemplate.deleteById(claz, id);
}

/**
* Delete the Entity using object.
* @param entity
*/

public void delete(Object entity) {
cassandraTemplate.delete(entity);
}

/**
* Deleting the list of entities
* @param entities
*/

public <T> void delete(List<T> entities) {
cassandraTemplate.delete(entities);
}

/**
* Deleting the all entities.
* @param claz
*/

public <T> void deleteAll(Class<T> claz) {
cassandraTemplate.deleteAll(claz);
}

/**
* Getting the all entities.
* @param claz
* @return List of entities
*/

public <T> List<T> findAll(Class<T> claz) {
return (List<T>) cassandraTemplate.selectAll(claz);
}

/**
* Getting the all entity values using specific id's data.
* @param ids
* @param claz
* @return
*/

public <T> List<T> findAll(List<Object> ids, Class<T> claz) {
return cassandraTemplate.selectBySimpleIds(claz, ids);
}

/**
* Getting the count of records.
* @param claz
* @return the count value.
*/

public <T> void truncate(Class<T> claz) {
cassandraTemplate.truncate(claz.getName());
}

/**
* Getting the count of records.
* @param claz
* @return the count value.
*/

public <T> long getCount(Class<T> claz) {
return cassandraTemplate.count(claz);
}


/**
* Checking the object exists or not.
* @param id
* @param claz
* @return true if the object exists in the database otherwise it will return false.
*/

public <T> boolean exists(Object id, Class<T> claz) {
return cassandraTemplate.exists(claz, id);
}

}
Entity Class:
com/ranga/entity/Employee.java
package com.ranga.entity;

import org.springframework.data.cassandra.mapping.Column;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.Table;

/**
* Employee Entity class.
* @author Ranga Reddy
* @version 1.0
*/


@Table(value="employee")
public class Employee {

@PrimaryKey(value="id")
private int id;

@Column(value="name")
private String name;

@Column(value="salary")
private float salary;

/**
* Default Constructor
*/

public Employee() {
super();
}

/**
* Parameterized Constructor
* @param id
* @param name
* @param salary
*/

public Employee(int id, String name, float salary) {
super();
this.id = id;
this.name = name;
this.salary = salary;
}


/**
* @return the id
*/

public int getId() {
return id;
}

/**
* @param id the id to set
*/

public void setId(int id) {
this.id = id;
}

/**
* @return the name
*/

public String getName() {
return name;
}

/**
* @param name the name to set
*/

public void setName(String name) {
this.name = name;
}

/**
* @return the salary
*/

public float getSalary() {
return salary;
}

/**
* @param salary the salary to set
*/

public void setSalary(float salary) {
this.salary = salary;
}

@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", salary=" + salary
+ "]";
}

}
Service and Impl classes:
com/ranga/service/EmployeeService.java
package com.ranga.service;

import java.util.List;

import com.ranga.entity.Employee;

/**
* Service interface for Employee to perform CRUD operation.
* @author Ranga Reddy
* @version 1.0
*/

public interface EmployeeService {
/**
* Used to Create the Employee Information
* @param employee
* @return {@link Employee}
*/

public Employee createEmployee(Employee employee);

/**
* Getting the Employee Information using Id
* @param id
* @return {@link Employee}
*/

public Employee getEmployee(int id);

/**
* Used to Update the Employee Information
* @param employee
* @return {@link Employee}
*/


public Employee updateEmployee(Employee employee);

/**
* Deleting the Employee Information using Id
* @param id
*/

public void deleteEmployee(int id);

/**
* Getting the All Employees information
* @return
*/

public List<Employee> getAllEmployees();
}

com/ranga/service/EmployeeServiceImpl.java
package com.ranga.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.ranga.dao.EmployeeDAO;
import com.ranga.entity.Employee;

/**
* Service Impl class for Employee to perform CRUD operation.
* @author Ranga Reddy
* @version 1.0
*/

public class EmployeeServiceImpl implements EmployeeService {

@Autowired
private EmployeeDAO employeeDAO;

/**
*
*/

public EmployeeServiceImpl() {
super();
}

@Override
@Transactional
public Employee createEmployee(Employee employee) {
return employeeDAO.createEmployee(employee);
}

@Override
@Transactional
public Employee getEmployee(int id) {
return employeeDAO.getEmployee(id);
}

@Override
@Transactional
public Employee updateEmployee(Employee employee) {
return employeeDAO.updateEmployee(employee);
}

@Override
@Transactional
public void deleteEmployee(int id) {
employeeDAO.deleteEmployee(id);
}

@Override
@Transactional
public List<Employee> getAllEmployees() {
return employeeDAO.getAllEmployees();
}
}
DAO and Impl classes:
com/ranga/dao/EmployeeDAO.java
package com.ranga.dao;

import java.util.List;

import com.ranga.entity.Employee;

/**
* DAO interface for Employee to perform CRUD operation.
* @author Ranga Reddy
* @version 1.0
*/

public interface EmployeeDAO {
/**
* Used to Create the Employee Information
* @param employee
* @return {@link Employee}
*/

public Employee createEmployee(Employee employee);

/**
* Getting the Employee Information using Id
* @param id
* @return {@link Employee}
*/

public Employee getEmployee(int id);

/**
* Used to Update the Employee Information
* @param employee
* @return {@link Employee}
*/


public Employee updateEmployee(Employee employee);

/**
* Deleting the Employee Information using Id
* @param id
*/

public void deleteEmployee(int id);

/**
* Getting the All Employees information
* @return
*/

public List<Employee> getAllEmployees();
}

com/ranga/dao/EmployeeDAOImpl.java
package com.ranga.dao;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import com.ranga.entity.Employee;
import com.ranga.util.MyCassandraTemplate;

/**
* DAOImpl class for Employee to perform CRUD operation.
* @author Ranga Reddy
* @version 1.0
*/

public class EmployeeDAOImpl implements EmployeeDAO {

@Autowired
private MyCassandraTemplate myCassandraTemplate;

@Override
public Employee createEmployee(Employee employee) {
return myCassandraTemplate.create(employee, Employee.class);
}

@Override
public Employee getEmployee(int id) {
return myCassandraTemplate.findById(id, Employee.class);
}

@Override
public Employee updateEmployee(Employee employee) {
return myCassandraTemplate.update(employee, Employee.class);
}

@Override
public void deleteEmployee(int id) {
myCassandraTemplate.deleteById(id, Employee.class);
}

@Override
public List<Employee> getAllEmployees() {
return myCassandraTemplate.findAll(Employee.class);
}
}
Spring Main Configuration file:
com/ranga/configuration/MainAppConfiguration.java
package com.ranga.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import com.ranga.dao.EmployeeDAO;
import com.ranga.dao.EmployeeDAOImpl;
import com.ranga.service.EmployeeService;
import com.ranga.service.EmployeeServiceImpl;
import com.ranga.util.CassandraUtil;
import com.ranga.util.MyCassandraTemplate;

/**
* This is the main configuration file to create the Beans.
* @author Ranga Reddy
* @version 1.0
*/


@Configuration
@Import(CassandraUtil.class)
public class MainAppConfiguration {

/**
* Creating the EmployeeService bean.
* @return {@link EmployeeService}
*/

@Bean
public EmployeeService getEmployeeService() {
return new EmployeeServiceImpl();
}

/**
* Creating the EmployeeDAO bean.
* @return {@link EmployeeDAO}
*/

@Bean
public EmployeeDAO getEmployeeDAO() {
return new EmployeeDAOImpl();
}

/**
* Creating the MyCassandraTemplate bean.
* @return {@link MyCassandraTemplate}
*/

@Bean
public MyCassandraTemplate getMyCassandraTemplate() {
return new MyCassandraTemplate();
}
}
Client Application
com/ranga/client/Application.java
package com.ranga.client;

import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.ranga.configuration.MainAppConfiguration;
import com.ranga.entity.Employee;
import com.ranga.service.EmployeeService;

/**
* Client Application to perform CRUD operations.
* @author Ranga Reddy
* @version 1.0
*/


public class Application {

@SuppressWarnings("resource")
public static void main(String[] args) {

// Getting the ApplicationContext
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(MainAppConfiguration.class);

//Getting the EmployeeService object.
EmployeeService employeeService = applicationContext.getBean(EmployeeService.class);

Employee employee = new Employee(1, "Ranga", 20000);

// Create the Employee information
employee = employeeService.createEmployee(employee);
System.out.println("After Creattion Employee Info: "+employee);

System.out.println("Displaying all Employee Info ");
// Getting All Employees information and printing
List<Employee> employees = employeeService.getAllEmployees();
employees.forEach(emp -> { System.out.println(emp);});

System.out.println("Updating the Employee Info: ");
// Updating the Employee information
employee.setName("Ranga Reddy");
employee.setSalary(40000);
employeeService.updateEmployee(employee);

// Getting the Employee information based on Id
employee = employeeService.getEmployee(employee.getId());
System.out.println("After Updation Employee Info: "+employee);

System.out.println("Deleting Employee Info ");
// Deleting the Employee Information
employeeService.deleteEmployee(employee.getId());
employee = employeeService.getEmployee(employee.getId());
System.out.println("After Deletion Employee Info: "+employee);
}
}

Output:
20:48:44.253 [main] DEBUG o.s.cassandra.core.CqlTemplate - executing [INSERT INTO employee(id,name,salary) VALUES (1,'Ranga',20000.0);]
After Creattion Employee Info: Employee [id=1, name=Ranga, salary=20000.0]
Displaying all Employee Info
Employee [id=1, name=Ranga, salary=20000.0]
Updating the Employee Info:
20:48:44.376 [main] DEBUG o.s.cassandra.core.CqlTemplate - executing [INSERT INTO employee(id,name,salary) VALUES (1,'Ranga Reddy',40000.0);]
20:48:44.382 [main] DEBUG o.s.cassandra.core.CqlTemplate - executing [SELECT * FROM employee WHERE id=1;]
After Updation Employee Info: Employee [id=1, name=Ranga Reddy, salary=40000.0]
Deleting Employee Info
20:48:44.391 [main] DEBUG o.s.cassandra.core.CqlTemplate - executing [DELETE FROM employee WHERE id=1;]
20:48:44.395 [main] DEBUG o.s.cassandra.core.CqlTemplate - executing [SELECT * FROM employee WHERE id=1;]
After Deletion Employee Info: null

4 comments:

Anurag Jain said...

Hi Ranga,

This was a nice and well explained post.
I have tried replicating the project but hitting the below issue -

java.lang.ClassNotFoundException: org.springframework.core.DefaultParameterNameDiscoverer
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1858)
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1709)
org.springframework.data.mapping.model.PreferredConstructorDiscoverer.(PreferredConstructorDiscoverer.java:38)
org.springframework.data.mapping.model.BasicPersistentEntity.(BasicPersistentEntity.java:92)
org.springframework.data.cassandra.mapping.BasicCassandraPersistentEntity.(BasicCassandraPersistentEntity.java:83)
org.springframework.data.cassandra.mapping.BasicCassandraMappingContext.createPersistentEntity(BasicCassandraMappingContext.java:123)
org.springframework.data.cassandra.mapping.BasicCassandraMappingContext.createPersistentEntity(BasicCassandraMappingContext.java:54)
org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:299)
org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:179)
org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:139)
org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:66)
org.springframework.data.cassandra.core.CassandraTemplate.getTableName(CassandraTemplate.java:217)
org.springframework.data.cassandra.core.CassandraTemplate.doInsert(CassandraTemplate.java:641)
org.springframework.data.cassandra.core.CassandraTemplate.insert(CassandraTemplate.java:237)
org.springframework.data.cassandra.core.CassandraTemplate.insert(CassandraTemplate.java:232)
org.jetset.estate.util.MyCassandraTemplate.create(MyCassandraTemplate.java:31)
org.jetset.estate.dao.EmployeeDAOImpl.createEmployee(EmployeeDAOImpl.java:16)
org.jetset.estate.service.EmployeeServiceImpl.createEmployee(EmployeeServiceImpl.java:25)
org.jetset.estate.HomeController.insertEmp(HomeController.java:57)

Please suggest.
Thanks.

java-quest said...

Is this code downloadable?

VR said...

Good example.

anmol singh said...

Nice article. Thanks for sharing such good inforamation.You can see some more good cassandra examples here
visit Casandra Tutorails