JPA/Hibernate Cascade Types Example Tutorial

In this tutorial, we will cover the different cascade types provided by JPA and Hibernate. Cascading is a vital feature in JPA and Hibernate that allows you to manage the state transitions of related entities automatically. We will explain the cascade types and then create a step-by-step tutorial to demonstrate these types using a Product entity.

Cascade Types in JPA and Hibernate

CascadeType.PERSIST

When an entity is persisted, all entities that are referenced by it will also be persisted.

CascadeType.MERGE

When an entity is merged, all entities that are referenced by it will also be merged.

CascadeType.REMOVE

When an entity is removed, all entities that are referenced by it will also be removed.

CascadeType.REFRESH

When an entity is refreshed, all entities that are referenced by it will also be refreshed.

CascadeType.DETACH

When an entity is detached, all entities that are referenced by it will also be detached.

CascadeType.ALL

Applies all cascade operations: PERSIST, MERGE, REMOVE, REFRESH, DETACH.

Step-by-Step Tutorial: Demonstrating Cascade Types

We will create a simple Hibernate application to demonstrate the different cascade types using a Product entity. This application will manage Product and Category entities, where a Category can have multiple Product entities.

Step 1: Setting Up the Hibernate Project

1.1 Create a Maven Project

  1. Open your IDE and create a new Maven project.

  2. Configure the pom.xml file:

Add the following dependencies to your 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>com.example</groupId>
    <artifactId>hibernate-cascade-example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.hibernate.orm</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>6.4.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.orm</groupId>
            <artifactId>hibernate-hikaricp</artifactId>
            <version>6.4.0.Final</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>
        <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.8.1</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

1.2 Configure Hibernate

Create a file named hibernate.cfg.xml in the src/main/resources directory with the following content:

<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/your_database_name</property>
        <property name="hibernate.connection.username">your_username</property>
        <property name="hibernate.connection.password">your_password</property>
        <property name="hibernate.hbm2ddl.auto">update</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>
    </session-factory>
</hibernate-configuration>

Replace your_database_name, your_username, and your_password with your MySQL database credentials.

Step 2: Creating Entities

2.1 Create Category Entity

Create a class named Category in the com.example.hibernateexample.model package:

package com.example.hibernateexample.model;

import jakarta.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
public class Category {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany(mappedBy = "category", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Product> products = new ArrayList<>();

    // Constructors, Getters, and Setters

    public Category() {
    }

    public Category(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public List<Product> getProducts() {
        return products;
    }

    public void setProducts(List<Product> products) {
        this.products = products;
    }

    public void addProduct(Product product) {
        products.add(product);
        product.setCategory(this);
    }

    public void removeProduct(Product product) {
        products.remove(product);
        product.setCategory(null);
    }
}

2.2 Create Product Entity

Create a class named Product in the com.example.hibernateexample.model package:

package com.example.hibernateexample.model;

import jakarta.persistence.*;

@Entity
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToOne
    @JoinColumn(name = "category_id")
    private Category category;

    // Constructors, Getters, and Setters

    public Product() {
    }

    public Product(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Category getCategory() {
        return category;
    }

    public void setCategory(Category category) {
        this.category = category;
    }
}

Step 3: Creating the Hibernate Utility Class

Create a HibernateUtil class in the com.example.hibernateexample.util package:

package com.example.hibernateexample.util;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {

    private static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
            Configuration configuration = new Configuration();
            configuration.configure("hibernate.cfg.xml");
            configuration.addAnnotatedClass(Category.class);
            configuration.addAnnotatedClass(Product.class);
            return configuration.buildSessionFactory(new StandardServiceRegistryBuilder()
                    .applySettings(configuration.getProperties()).build());
        } 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();
    }
}

Step 4: Demonstrating Cascade Operations

4.1 Create a DAO Class

Create a DAO class to demonstrate cascade operations in the com.example.hibernateexample.dao package:

package com.example.hibernateexample.dao;

import com.example.hibernateexample.model.Category;
import com.example.hibernateexample.model.Product;
import com.example.hibernateexample.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;

public class CategoryDao {

    public void saveCategoryWithProducts() {
        Transaction transaction = null;
        try (Session session = HibernateUtil.getSessionFactory().openSession()) {
            transaction = session.beginTransaction();

            Category category = new Category("Electronics");
            Product product1 = new Product("Laptop");
            Product product2 = new Product("Smartphone");

            category.addProduct(product1);
            category.addProduct(product2);

            session.save(category);

            transaction.commit();
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        }
    }

    public void removeProductFromCategory(Long categoryId, Long productId) {
        Transaction transaction = null;
        try (Session session = HibernateUtil.getSessionFactory().openSession()) {
            transaction = session.beginTransaction();



            Category category = session.get(Category.class, categoryId);
            if (category != null) {
                category.getProducts().removeIf(product -> product.getId().equals(productId));
            }

            transaction.commit();
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        }
    }

    public void deleteCategory(Long categoryId) {
        Transaction transaction = null;
        try (Session session = HibernateUtil.getSessionFactory().openSession()) {
            transaction = session.beginTransaction();

            Category category = session.get(Category.class, categoryId);
            if (category != null) {
                session.delete(category);
            }

            transaction.commit();
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        }
    }
}

4.2 Create a Main Class

Create a Main class in the com.example.hibernateexample package to run the DAO methods:

package com.example.hibernateexample;

import com.example.hibernateexample.dao.CategoryDao;

public class Main {
    public static void main(String[] args) {
        CategoryDao categoryDao = new CategoryDao();

        // Save category with products
        categoryDao.saveCategoryWithProducts();
        System.out.println("Category and Products saved.");

        // Uncomment the following lines to test other operations

        // Remove a product from category
        // categoryDao.removeProductFromCategory(1L, 2L);
        // System.out.println("Product removed from Category.");

        // Delete a category
        // categoryDao.deleteCategory(1L);
        // System.out.println("Category deleted.");
    }
}

Conclusion

In this tutorial, we covered the different cascade types provided by JPA and Hibernate and demonstrated how to use them in a Hibernate application. We created Category and Product entities and a CategoryDao class to handle database operations. We tested the cascade operations in a Main class. By following this structure, you can extend and customize the application as needed.

Comments