Hibernate with Cassandra Tutorial

This tutorial will guide you through setting up and using Hibernate with Apache Cassandra, a highly scalable NoSQL database. We will demonstrate how to configure Hibernate to interact with Cassandra and perform basic CRUD operations.

Introduction

Apache Cassandra is a highly scalable, distributed NoSQL database designed to handle large amounts of data across many commodity servers without any single point of failure. Integrating Hibernate with Cassandra allows you to leverage Hibernate's ORM capabilities with Cassandra's scalability.

In this tutorial, we will:

  1. Set up a Maven project with necessary dependencies.
  2. Configure Hibernate to connect to Cassandra.
  3. Create an entity class (Product).
  4. Perform basic CRUD operations using Hibernate and Cassandra.

Step 1: Set Up Your Project

1.1 Create a Maven Project

Open your IDE and create a new Maven project.

1.2 Add Dependencies

Update your pom.xml file to include dependencies for Hibernate and Cassandra.

<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>com.example</groupId>
    <artifactId>hibernate-cassandra-example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- Hibernate ORM -->
        <dependency>
            <groupId>org.hibernate.orm</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>6.4.0.Final</version>
        </dependency>

        <!-- Cassandra Connector -->
        <dependency>
            <groupId>com.datastax.oss</groupId>
            <artifactId>java-driver-core</artifactId>
            <version>4.13.0</version>
        </dependency>

        <!-- Hibernate OGM for NoSQL databases -->
        <dependency>
            <groupId>org.hibernate.ogm</groupId>
            <artifactId>hibernate-ogm-core</artifactId>
            <version>5.4.1.Final</version>
        </dependency>

        <!-- Hibernate OGM Cassandra dialect -->
        <dependency>
            <groupId>org.hibernate.ogm</groupId>
            <artifactId>hibernate-ogm-datastore-cassandra</artifactId>
            <version>5.4.1.Final</version>
        </dependency>

        <!-- SLF4J for logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.32</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.32</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.10.1</version>
                <configuration>
                    <source>21</source>
                    <target>21</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Step 2: Configure Hibernate

2.1 Create hibernate.cfg.xml

Create a hibernate.cfg.xml file in the src/main/resources directory to configure the connection settings for Cassandra and Hibernate properties.

<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
    <session-factory>
        <!-- Connection properties -->
        <property name="hibernate.ogm.datastore.provider">cassandra</property>
        <property name="hibernate.ogm.datastore.host">127.0.0.1</property>
        <property name="hibernate.ogm.datastore.port">9042</property>
        <property name="hibernate.ogm.datastore.database">mykeyspace</property>
        <property name="hibernate.ogm.datastore.username">cassandra</property>
        <property name="hibernate.ogm.datastore.password">cassandra</property>

        <!-- Hibernate properties -->
        <property name="hibernate.dialect">org.hibernate.ogm.datastore.cassandra.CassandraDialect</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>

        <!-- Entity mappings -->
        <mapping class="com.example.entity.Product"/>
    </session-factory>
</hibernate-configuration>

Replace 127.0.0.1, 9042, mykeyspace, cassandra, and cassandra with your Cassandra database connection details.

Explanation:

  • hibernate.ogm.datastore.provider specifies the NoSQL datastore provider, which is Cassandra in this case.
  • hibernate.ogm.datastore.host and hibernate.ogm.datastore.port specify the Cassandra host and port.
  • hibernate.ogm.datastore.database specifies the keyspace to connect to.
  • hibernate.ogm.datastore.username and hibernate.ogm.datastore.password specify the Cassandra credentials.
  • hibernate.dialect specifies the dialect for Cassandra.
  • hibernate.show_sql and hibernate.format_sql properties are used to display and format the generated CQL statements.
  • The <mapping class="com.example.entity.Product"/> line maps the Product entity to the Cassandra keyspace.

Step 3: Create the Entity Class

Create an entity class Product that will be mapped to a table in the Cassandra keyspace. This class uses annotations to define the entity and its fields.

package com.example.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "product")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private String id;
    private String name;
    private double price;

    // Getters and setters
    public String getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}

Explanation:

  • The @Entity annotation specifies that the class is an entity and is mapped to a table in the Cassandra keyspace.
  • The @Table(name = "product") annotation specifies the table name in the Cassandra keyspace.
  • The @Id annotation specifies the primary key of the entity.
  • The @GeneratedValue(strategy = GenerationType.IDENTITY) annotation specifies that the primary key is generated automatically.

Step 4: Create the DAO Class

Create a DAO class to manage database operations using Hibernate.

4.1 Create ProductDAO

package com.example.dao;

import com.example.entity.Product;
import com.example.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;

import java.util.List;

public class ProductDAO {

    public void saveProduct(Product product) {
        Transaction transaction = null;
        try (Session session = HibernateUtil.getSessionFactory().openSession()) {
            transaction = session.beginTransaction();
            session.save(product);
            transaction.commit();
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        }
    }

    public void updateProduct(Product product) {
        Transaction transaction = null;
        try (Session session = HibernateUtil.getSessionFactory().openSession()) {
            transaction = session.beginTransaction();
            session.update(product);
            transaction.commit();
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        }
    }

    public Product getProductById(String id) {
        try (Session session = HibernateUtil.getSessionFactory().openSession()) {
            return session.get(Product.class, id);
        }
    }

    public List<Product> getAllProducts() {
        try (Session session = HibernateUtil.getSessionFactory().openSession()) {
            return session.createQuery("from Product", Product.class).list();
        }
    }

    public void deleteProduct(String id) {
        Transaction transaction = null;
        try (Session session = HibernateUtil.getSessionFactory().openSession()) {
            transaction = session.beginTransaction();
            Product product = session.get(Product.class, id);
            if (product != null) {
                session.delete(product);
                System.out.println("Product is deleted");
            }
            transaction.commit();
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        }
    }
}

Explanation:

  • The ProductDAO class contains methods to interact with the Cassandra database using Hibernate.
  • The saveProduct method saves a new product to the database.
  • The updateProduct method updates an existing product in the database.
  • The getProductById method retrieves a product by its ID.
  • The `get

AllProducts` method retrieves all products from the database.

  • The deleteProduct method deletes a product by its ID.

Step 5: Demonstrate CRUD Operations

Create a main class to demonstrate the CRUD operations using the Product entity and ProductDAO class.

5.1 Create MainApp

package com.example.main;

import com.example.dao.ProductDAO;
import com.example.entity.Product;
import com.example.util.HibernateUtil;

import java.util.List;

public class MainApp {
    public static void main(String[] args) {
        ProductDAO productDAO = new ProductDAO();

        // Create new products
        Product product1 = new Product();
        product1.setName("Laptop");
        product1.setPrice(1000.00);

        Product product2 = new Product();
        product2.setName("Phone");
        product2.setPrice(500.00);

        // Save products
        productDAO.saveProduct(product1);
        productDAO.saveProduct(product2);

        // Update product
        product1.setPrice(1200.00);
        productDAO.updateProduct(product1);

        // Get product by ID
        Product retrievedProduct = productDAO.getProductById(product1.getId());
        System.out.println("Retrieved Product: " + retrievedProduct.getName() + " - " + retrievedProduct.getPrice());

        // Get all products
        List<Product> products = productDAO.getAllProducts();
        System.out.println("All Products:");
        products.forEach(product -> System.out.println(product.getName() + " - " + product.getPrice()));

        // Delete product
        productDAO.deleteProduct(product2.getId());

        // Get all products after deletion
        products = productDAO.getAllProducts();
        System.out.println("All Products after deletion:");
        products.forEach(product -> System.out.println(product.getName() + " - " + product.getPrice()));

        // Shut down the SessionFactory
        HibernateUtil.shutdown();
    }
}

Explanation:

  • The MainApp class demonstrates CRUD operations using the ProductDAO class.
  • The saveProduct method is called to save new products to the database.
  • The updateProduct method is called to update an existing product.
  • The getProductById method is called to retrieve a product by its ID.
  • The getAllProducts method is called to retrieve all products from the database.
  • The deleteProduct method is called to delete a product by its ID.
  • The getAllProducts method is called again to retrieve all products after the deletion.

5.2 Create HibernateUtil Class

Create a utility class HibernateUtil to manage the Hibernate SessionFactory.

package com.example.util;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {
    private static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
            // Load the configuration and build the SessionFactory
            return new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public static void shutdown() {
        getSessionFactory().close();
    }
}

Explanation:

  • The HibernateUtil class provides a singleton SessionFactory and a method to shut it down.
  • The buildSessionFactory method loads the Hibernate configuration from hibernate.cfg.xml and builds the SessionFactory.

Step 6: Run the Application

  1. Ensure your Cassandra database is running and the connection details in hibernate.cfg.xml are correct.
  2. Create the necessary keyspace and table in Cassandra if they do not exist.
  3. Run the MainApp class to perform CRUD operations and print the results.

Sample Output

If everything is set up correctly, running the MainApp class should produce output similar to the following:

Retrieved Product: Laptop - 1200.0
All Products:
Laptop - 1200.0
Phone - 500.0
Product is deleted
All Products after deletion:
Laptop - 1200.0

Conclusion

In this tutorial, we have successfully demonstrated how to integrate Hibernate with Cassandra, a highly scalable NoSQL database. We configured the project dependencies, created an entity class, set up the Hibernate configuration file, and demonstrated basic CRUD operations using Hibernate and Cassandra. This guide provides a solid foundation for using Hibernate with Cassandra in your applications.


Comments