How do I write a simple JPQL query using Hibernate?

To write a simple JPQL (Java Persistence Query Language) query using Hibernate, follow these steps:

Example: Basic JPQL Query

For example, consider we have an entity: Employee

package org.kodejava.hibernate;

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

@Entity
@Table(name = "employee")
public class Employee {
    @Id
    private Long id;
    private String name;
    private String department;
    private Double salary;

    // Getters and setters
}

1. Write the JPQL Query

A JPQL query allows you to query entities in an object-oriented way. For instance, fetching employees with a salary greater than 50000:

String jpqlQuery = "SELECT e FROM Employee e WHERE e.salary > :salary";

2. Using EntityManager to Execute the Query

You need to use the EntityManager to create and execute a JPQL query. Here is how you can do it:

package org.kodejava.hibernate;

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import jakarta.persistence.TypedQuery;
import java.util.List;

public class JPQLExample {
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("persistence-unit-name");
        EntityManager em = emf.createEntityManager();

        try {
            em.getTransaction().begin();

            // JPQL query
            String jpqlQuery = "SELECT e FROM Employee e WHERE e.salary > :salary";

            // TypedQuery to avoid type casting
            TypedQuery<Employee> query = em.createQuery(jpqlQuery, Employee.class);
            query.setParameter("salary", 50000.0);

            // Executing the query and fetching the results
            List<Employee> employees = query.getResultList();

            // Display the result
            for (Employee employee : employees) {
                System.out.println("Employee: " + employee.getName() + ", Salary: " + employee.getSalary());
            }

            em.getTransaction().commit();
        } finally {
            em.close();
            emf.close();
        }
    }
}

Explanation of the Code

  1. JPQL Query:
    • "SELECT e FROM Employee e WHERE e.salary > :salary" is the JPQL query.
    • e is an alias for the entity. Employee
    • :salary is a named parameter.
  2. EntityManager:
    • The EntityManager is used to create queries and execute them.
    • The createQuery() method takes the JPQL query string and the result type.
  3. TypedQuery:
    • A TypedQuery is preferred for type safety and avoids casting the result.
  4. Parameter Binding:
    • setParameter() binds the value to the named parameter in the JPQL query.
  5. Fetching Results:
    • getResultList() fetches the results as a list of entities matching the query condition.

Additional Notes

  • JPQL uses the entity and its fields, not the database table or column names.
  • Make sure your is correctly configured with the persistence unit name. persistence.xml

This is how you write and execute a simple JPQL query with Hibernate.

How do I configure Hibernate with an H2 in-memory database?

Configuring Hibernate with an H2 in-memory database is quite straightforward. Below is a guide for configuring Hibernate with an H2 database in a Spring Boot or standalone Jakarta EE project.


Configuration for Hibernate with H2 in-memory database

1. Add Dependencies

Ensure you have the necessary dependencies in your project. For a Maven project, include the following in your pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

If you’re using Jakarta EE without Spring, you can directly include:

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

<!-- H2 Database -->
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

2. Configure application.yml or application.properties (if using Spring Boot)

For application.properties:

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true

For application.yml:

spring:
  datasource:
    url: jdbc:h2:mem:testdb
    driver-class-name: org.h2.Driver
    username: sa
    password: 
  jpa:
    database-platform: org.hibernate.dialect.H2Dialect
  h2:
    console:
      enabled: true

3. Standalone Hibernate Configuration (Non-Spring)

Create a hibernate.cfg.xml file in the resources folder:

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

<hibernate-configuration>
    <session-factory>
        <!-- JDBC Database connection settings -->
        <property name="hibernate.connection.driver_class">org.h2.Driver</property>
        <property name="hibernate.connection.url">jdbc:h2:mem:testdb</property>
        <property name="hibernate.connection.username">sa</property>
        <property name="hibernate.connection.password"></property>

        <!-- Dialect -->
        <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>

        <!-- Show SQL -->
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>

        <!-- Drop and re-create the database schema on startup -->
        <property name="hibernate.hbm2ddl.auto">create-drop</property>
    </session-factory>
</hibernate-configuration>

4. Entity Classes

Define your Hibernate/JPA entity classes. An example:

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

@Entity
public class Student {

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

    private String name;
    private int age;

    // Getters and Setters
}

5. H2 Console (Optional, Spring Boot only)

To access the H2 console for debugging, enable it as shown in the Spring configuration. By default, the H2 console will be available at `http://localhost:8080/h2-console`. You can login with:

  • JDBC URL: jdbc:h2:mem:testdb
  • Username: sa
  • Password: (leave it blank)

6. Configure EntityManagerFactory or SessionFactory (Standalone)

For standalone Hibernate usage, you can programmatically configure a SessionFactory. An example:

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

public class HibernateUtil {

    private static final SessionFactory sessionFactory;

    static {
        try {
            sessionFactory = new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

After completing these steps, you will have a working setup with Hibernate and an H2 in-memory database. You can now run your application, and the database schema will be automatically created and dropped upon application startup/shutdown.

How do I use SessionFactory and Session in Hibernate 6?

Hibernate ORM 6 introduces several changes to its API compared to previous versions, especially in how SessionFactory and Session are used due to compliance with Jakarta EE and its updated imports (jakarta.persistence.*).
Here’s a simple guide to using SessionFactory and Session in Hibernate 6:

1. Add Hibernate Dependencies

Make sure to include the Hibernate 6 dependencies in your project. If you’re using Maven, the dependency would look like this:

<dependency>
    <groupId>org.hibernate.orm</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>6.4.4.Final</version>
</dependency>

2. Configure Hibernate

Use or Properties for configuration:hibernate.cfg.xml

Example: hibernate.cfg.xml

<hibernate-configuration>
    <session-factory>
        <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
        <property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
        <property name="hibernate.connection.url">jdbc:postgresql://localhost:5432/your_database</property>
        <property name="hibernate.connection.username">your_username</property>
        <property name="hibernate.connection.password">your_password</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.hbm2ddl.auto">update</property>
    </session-factory>
</hibernate-configuration>

Alternatively, use Java configuration with Properties:

Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
properties.put("hibernate.connection.driver_class", "org.postgresql.Driver");
properties.put("hibernate.connection.url", "jdbc:postgresql://localhost:5432/your_database");
properties.put("hibernate.connection.username", "your_username");
properties.put("hibernate.connection.password", "your_password");
properties.put("hibernate.show_sql", "true");
properties.put("hibernate.hbm2ddl.auto", "update");

3. Create a SessionFactory

Starting with Hibernate 6, the SessionFactory should be built using the StandardServiceRegistryBuilder and MetadataSources.

Here’s an example:

Using hibernate.cfg.xml:

package org.kodejava.hibernate;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;

public class HibernateUtil {

    private static SessionFactory sessionFactory;

    static {
        // Build the ServiceRegistry using hibernate.cfg.xml
        StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
                .configure("hibernate.cfg.xml") // Loads hibernate.cfg.xml by default
                .build();

        try {
            // Build SessionFactory
            sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
        } catch (Exception e) {
            StandardServiceRegistryBuilder.destroy(registry);
            throw new ExceptionInInitializerError("SessionFactory build failed: " + e.getMessage());
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

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

Using Java configuration with Properties:

package org.kodejava.hibernate;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;

import java.util.Properties;

public class HibernateUtil {

    private static SessionFactory sessionFactory;

    static {
        // Create Hibernate properties
        Properties properties = new Properties();
        properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
        properties.put("hibernate.connection.driver_class", "org.postgresql.Driver");
        properties.put("hibernate.connection.url", "jdbc:postgresql://localhost:5432/your_database");
        properties.put("hibernate.connection.username", "your_username");
        properties.put("hibernate.connection.password", "your_password");
        properties.put("hibernate.show_sql", "true");
        properties.put("hibernate.hbm2ddl.auto", "update");

        // Build the ServiceRegistry
        StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
                .applySettings(properties)
                .build();

        try {
            // Build SessionFactory
            sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
        } catch (Exception e) {
            StandardServiceRegistryBuilder.destroy(registry);
            throw new ExceptionInInitializerError("SessionFactory build failed: " + e.getMessage());
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

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

4. Use SessionFactory to Get a Session

A Session represents a single unit of work with the database. In Hibernate 6, the usage involves a similar pattern to previous versions.

package org.kodejava.hibernate;

import org.hibernate.Session;
import org.hibernate.SessionFactory;

public class App {
    public static void main(String[] args) {
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();

        // Obtain a session
        try (Session session = sessionFactory.openSession()) {
            // Begin transaction
            session.beginTransaction();

            // Perform operations (e.g., save entities)
            MyEntity entity = new MyEntity();
            entity.setName("Example");
            session.persist(entity);

            // Commit the transaction
            session.getTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // Shutdown the session factory
            HibernateUtil.shutdown();
        }
    }
}

5. Entity Example

Ensure your entity classes are annotated correctly with Jakarta Persistence annotations (jakarta.persistence.*).

package org.kodejava.hibernate;

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

@Entity
public class MyEntity {

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

    private String name;

    // Getters and Setters
    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;
    }
}

Key Updates in Hibernate 6

  1. Jakarta Imports: Hibernate moved from javax.persistence.* to jakarta.persistence.*.
  2. Default Configuration: The APIs are adaptive, but the configuration process is largely unchanged.
  3. Session Persistence: The Session.persist(Object) method is preferred over deprecated methods like save(Object).

By following these steps, you can effectively use SessionFactory and Session in Hibernate 6 for your application.

How do I map a Java class to a database table using JPA annotations?

To map a Java class to a database table using JPA annotations, you primarily use annotations provided by jakarta.persistence. Here is a step-by-step guide:

Key annotations for mapping:

  1. @Entity
    Marks the class as an entity that is mapped to a table.
  2. @Table (optional)
    Specifies the table name in the database. If omitted, the default table name is the class name.
  3. @Id
    Marks a field as the primary key.
  4. @GeneratedValue (optional)
    Specifies how the primary key value is generated (e.g., AUTO, SEQUENCE).
  5. @Column (optional)
    Represents a column in the table, providing options to customize the name, length, nullable flag, etc.
  6. Additional mapping annotations for relationships:
    For relationships between tables (e.g., one-to-many, many-to-one, etc.), you can use @OneToMany, @ManyToOne, @OneToOne, and @ManyToMany.

Example: Mapping a simple class

Here’s an example of a Java class mapped to a database table using JPA annotations:

package com.example;

import jakarta.persistence.*;

@Entity
@Table(name = "students") // Optional; defaults to "Student"
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // Auto-generate primary key
    private Long id;

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

    @Column(name = "email", unique = true, length = 150)
    private String email;

    @Column(name = "age", nullable = false)
    private int age;

    // Default constructor (needed by JPA)
    public Student() {
    }

    // Constructor with parameters and Getters/Setters
    public Student(String name, String email, int age) {
        this.name = name;
        this.email = email;
        this.age = age;
    }

    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 getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                '}';
    }
}

Explanation of the example:

  1. @Entity
    Declares the class as an entity tied to a database table.
  2. @Table(name = "students")
    Specifies the table name as students. If omitted, the table name would default to the class name Student.
  3. @Id and @GeneratedValue
    Defines a primary key and specifies how values are generated. Here, GenerationType.IDENTITY lets the database auto-increment the key.
  4. @Column(name = "full_name", nullable = false, length = 100)
    Maps the name property to the full_name column in the table, defines the column as non-nullable, and limits its length to 100 characters.
  5. @Column(name = "email", unique = true, length = 150)
    The email column is set to be unique, ensuring no duplicate email addresses.

Save and persist the entity:

The class can now be used with JPA to persist records in the database. For instance:

Student student = new Student("John Doe", "[email protected]", 25);

EntityManagerFactory emf = Persistence.createEntityManagerFactory("example-pu");
EntityManager em = emf.createEntityManager();

em.getTransaction().begin();
em.persist(student);  // Insert the record into the database
em.getTransaction().commit();

em.close();
emf.close();

Make sure to configure your file with your database connection details. persistence.xml


Maven Dependencies

<dependencies>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>6.4.4.Final</version>
    </dependency>
    <dependency>
        <groupId>jakarta.persistence</groupId>
        <artifactId>jakarta.persistence-api</artifactId>
        <version>3.1.0</version>
    </dependency>
</dependencies>

Maven Central Maven Central

How do I perform basic CRUD operations using Hibernate 6?

Basic CRUD operations with Hibernate 6 involve creating, reading, updating, and deleting records in a database using Hibernate ORM. Hibernate simplifies these operations through its API.

Below is an explanation of each CRUD operation along with corresponding examples:

1. Create (Insert)

To save a new object in the database, you use the persist() or save() method provided by Hibernate.

SessionFactory factory = new Configuration()
                .configure("hibernate.cfg.xml")
                .addAnnotatedClass(Student.class)
                .buildSessionFactory();

try (Session session = factory.openSession()) {
    // Create a new student entity
    Student student = new Student("Jane Doe");

    // Start a transaction
    session.beginTransaction();

    // Save the entity to the database
    session.persist(student);

    // Commit the transaction
    session.getTransaction().commit();

    System.out.println("Student saved successfully with ID: " + student.getId());
} finally {
    factory.close();
}

2. Read (Retrieve)

Hibernate’s get() or find() method is used to retrieve data from the database. You can fetch an object by its primary key.

try (Session session = factory.openSession()) {
    // Start a transaction (optional if only querying)
    session.beginTransaction();

    // Retrieve a student by their primary key (ID)
    int studentId = 1;  // Example ID
    Student retrievedStudent = session.get(Student.class, studentId);

    System.out.println("Retrieved Student: " + retrievedStudent);

    // Commit the transaction
    session.getTransaction().commit();
}

3. Update

To modify an existing object in the database, you first retrieve it, make changes to its fields, and then let Hibernate update it within a transaction.

try (Session session = factory.openSession()) {
    // Start a transaction
    session.beginTransaction();

    // Retrieve the student entity we want to update
    int studentId = 1;  // Example ID
    Student studentToUpdate = session.get(Student.class, studentId);

    // Modify the entity (e.g., update the name)
    if (studentToUpdate != null) {
        studentToUpdate.setName("Updated Name");
    }

    // Hibernate automatically tracks changes and applies them during commit
    session.getTransaction().commit();

    System.out.println("Student updated successfully.");
}

4. Delete

To delete an object, retrieve it first and use the delete() method to remove it from the database.

try (Session session = factory.openSession()) {
    // Start a transaction
    session.beginTransaction();

    // Retrieve the student to delete by their primary key
    int studentId = 1;
    Student studentToDelete = session.get(Student.class, studentId);

    // Delete the entity if it exists
    if (studentToDelete != null) {
        session.delete(studentToDelete);
        System.out.println("Student deleted successfully.");
    }

    // Commit the transaction
    session.getTransaction().commit();
}

Keynotes for Hibernate 6:

  1. Ensure you have the correct Hibernate dependencies in pom.xml (for Maven) or build.gradle (for Gradle).
  2. You must configure hibernate.cfg.xml, including database connection properties and mapping annotated classes.
  3. Always manage your Hibernate Session and SessionFactory carefully, and close them when done to free resources.
  4. Hibernate 6 has slight differences in config (e.g., Jakarta imports). Ensure you’re using the correct versions of annotations and configs (jakarta.persistence instead of javax.persistence).

For the provided code, it already demonstrates correct usage of creating a SessionFactory, opening a Session, performing a transaction for persist(), and closing resources. The same principles apply for all CRUD operations—use beginTransaction(), perform the operation, and commit() the transaction.


Maven Dependencies

<dependencies>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>6.4.4.Final</version>
    </dependency>
</dependencies>

Maven Central