CRUD Operations with Hibernate (Create, Read, Update, Delete)

This is a hands-on lesson demonstrating how to perform basic CRUD operations using Hibernate. You'll learn how to save new objects to the database (Create), retrieve objects (Read), modify existing objects (Update), and delete objects (Delete) using Hibernate's API.


Hibernate Entity Mapping Explained

Defining Entities and Mapping

In Hibernate, an Entity represents a table in your database. Mapping defines how your Java classes (Entities) relate to the database tables and their columns. This process involves specifying which class represents which table, and which fields within the class represent which columns in the table. Annotations are a common and convenient way to achieve this mapping in Java.

Hibernate uses this mapping information to:

  • Automatically create database schema (if configured to do so).
  • Translate Java objects into database rows (and vice versa).
  • Construct SQL queries based on your object-oriented model.

Creating Java Classes and Mapping with Annotations

Here's how you can create Java classes (Entities) to represent database tables and use annotations to map them using Hibernate:

Example: Product Entity

Consider a database table named products with columns: id, name, description, and price.

 import javax.persistence.*;

@Entity
@Table(name = "products")
public class Product {

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

    @Column(name = "name", nullable = false, length = 255)
    private String name;

    @Column(name = "description", columnDefinition = "TEXT")
    private String description;

    @Column(name = "price", precision = 10, scale = 2)
    private Double price;

    // Constructors, Getters, and Setters (omitted for brevity)

    public Product() {} // Important:  A no-argument constructor is required by Hibernate.

    public Product(String name, String description, Double price) {
        this.name = name;
        this.description = description;
        this.price = price;
    }

    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 String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Double getPrice() {
        return price;
    }

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

Explanation of Annotations:

  • @Entity: Marks the class as a JPA (Java Persistence API) entity. This tells Hibernate that this class represents a table in the database.
  • @Table(name = "products"): Specifies the name of the database table to which this entity is mapped. If omitted, Hibernate will assume the table name is the same as the class name (Product). It's good practice to explicitly define the table name.
  • @Id: Marks the id field as the primary key of the table.
  • @GeneratedValue(strategy = GenerationType.IDENTITY): Specifies how the primary key value is generated. GenerationType.IDENTITY indicates that the database will auto-generate the primary key (e.g., using an auto-increment column). Other strategies include AUTO, SEQUENCE, and TABLE.
  • @Column(name = "name", nullable = false, length = 255): Maps the name field to the name column in the table.
    • name: Specifies the column name. If omitted, Hibernate uses the field name.
    • nullable = false: Indicates that the column cannot be null in the database.
    • length = 255: Specifies the maximum length of the column.
  • @Column(name = "description", columnDefinition = "TEXT"): Maps the description field to the description column.
    • columnDefinition = "TEXT": Allows you to define the specific data type of the column. In this case, it's defined as TEXT, which is suitable for storing longer text.
  • @Column(name = "price", precision = 10, scale = 2): Maps the price field to the price column.
    • precision = 10: Defines the total number of digits allowed for the price.
    • scale = 2: Defines the number of digits after the decimal point.

Important Considerations:

  • Getters and Setters: Hibernate requires getter and setter methods for all persistent fields (fields mapped to database columns).
  • No-Argument Constructor: Hibernate also requires a no-argument (default) constructor for each entity class. This is used for creating instances during data retrieval.
  • Data Types: Choose appropriate Java data types for your fields to match the corresponding database column types.
  • Relationships: For representing relationships between tables (e.g., one-to-many, many-to-one), use annotations like @OneToMany, @ManyToOne, @ManyToMany.
  • Cascade Types: Understand CascadeTypes (e.g., CascadeType.ALL, CascadeType.PERSIST, CascadeType.REMOVE) which control how operations on a parent entity affect related child entities.
  • Lazy Loading: Consider lazy loading (FetchType.LAZY) for relationships to improve performance, especially when dealing with large datasets.