Criteria API

Learn how to build queries programmatically using Hibernate's Criteria API. This approach is useful for constructing dynamic queries based on runtime conditions. We'll cover the basics of building criteria queries and executing them.


Setting up a Hibernate Criteria API Development Environment

This guide provides instructions for setting up a development environment for working with Hibernate and the Criteria API in Java. It covers necessary libraries, database configurations, and project dependencies using Maven or Gradle.

1. Prerequisites

Before starting, ensure you have the following:

  • Java Development Kit (JDK): Version 8 or later is recommended.
  • IDE (Integrated Development Environment): Eclipse, IntelliJ IDEA, or NetBeans are popular choices.
  • Database: Choose a database (e.g., MySQL, PostgreSQL, H2) and have it installed and running. You'll need the database driver JAR file.
  • Build Tool: Maven or Gradle for dependency management.

2. Project Setup

Create a new Java project using your chosen IDE and build tool.

3. Dependency Management (Maven)

If you're using Maven, add the following dependencies to your pom.xml file:

 <dependencies>

                <!-- Hibernate Core -->
                <dependency>
                    <groupId>org.hibernate.orm</groupId>
                    <artifactId>hibernate-core</artifactId>
                    <version>6.4.0.Final</version> <!-- Use the latest version -->
                </dependency>

                <!-- Database Driver (MySQL example) -->
                <dependency>
                    <groupId>com.mysql</groupId>
                    <artifactId>mysql-connector-j</artifactId>
                    <version>8.3.0</version> <!-- Use the appropriate version for your MySQL server -->
                </dependency>


                <!-- SLF4J API for logging -->
                <dependency>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                    <version>2.0.9</version>
                </dependency>

                <!-- SLF4J simple logger implementation -->
                <dependency>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-simple</artifactId>
                    <version>2.0.9</version>
                    <scope>runtime</scope>
                </dependency>

                <!-- Jakarta Persistence API -->
                <dependency>
                    <groupId>jakarta.persistence</groupId>
                    <artifactId>jakarta.persistence-api</artifactId>
                    <version>3.1.0</version>
                </dependency>

            </dependencies> 

4. Dependency Management (Gradle)

If you're using Gradle, add the following dependencies to your build.gradle file:

 dependencies {
                // Hibernate Core
                implementation 'org.hibernate.orm:hibernate-core:6.4.0.Final' // Use the latest version

                // Database Driver (MySQL example)
                implementation 'com.mysql:mysql-connector-j:8.3.0' // Use the appropriate version for your MySQL server

                // SLF4J API for logging
                implementation 'org.slf4j:slf4j-api:2.0.9'

                // SLF4J simple logger implementation
                runtimeOnly 'org.slf4j:slf4j-simple:2.0.9'

                // Jakarta Persistence API
                implementation 'jakarta.persistence:jakarta.persistence-api:3.1.0'
            } 

5. Database Configuration

Create a Hibernate configuration file (hibernate.cfg.xml) or use programmatic configuration to define your database connection details. The hibernate.cfg.xml file should be placed in your src/main/resources directory.

Example hibernate.cfg.xml (MySQL)

 <!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>
                    <!-- Database connection settings -->
                    <property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
                    <property name="connection.url">jdbc:mysql://localhost:3306/your_database_name</property>
                    <property name="connection.username">your_username</property>
                    <property name="connection.password">your_password</property>

                    <!-- JDBC connection pool (use the built-in) -->
                    <property name="connection.pool_size">10</property>

                    <!-- Dialect for your database -->
                    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

                    <!-- Enable Hibernate's automatic session context management -->
                    <property name="current_session_context_class">thread</property>

                    <!-- Disable the second-level cache  -->
                    <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

                    <!-- Echo all executed SQL to stdout -->
                    <property name="show_sql">true</property>

                    <!-- Drop and re-create the database schema on startup -->
                    <property name="hbm2ddl.auto">update</property>

                    <!-- Mappings -->
                    <mapping class="your.package.name.YourEntity"/>
                    <!-- Add more mapping classes here -->

                </session-factory>
            </hibernate-configuration> 

Important Configuration Settings:

  • connection.driver_class: The fully qualified name of your database driver class.
  • connection.url: The JDBC URL for connecting to your database. Replace your_database_name, your_username, and your_password with your actual credentials.
  • dialect: The Hibernate dialect for your specific database. This is crucial for Hibernate to generate correct SQL. See the Hibernate documentation for available dialects.
  • hbm2ddl.auto: Controls how Hibernate handles the database schema.
    • create: Drops and recreates the schema on each startup. Use with caution, as it will erase your data.
    • update: Updates the schema based on your entity mappings. Adds new tables and columns, but doesn't delete existing ones. Generally a safer option for development.
    • create-drop: Creates the schema on startup and drops it when the SessionFactory is closed.
    • validate: Validates the schema against your entity mappings and throws an exception if there are discrepancies.
    • none: Does nothing. You are responsible for managing the database schema.
  • mapping class="your.package.name.YourEntity": Specifies the fully qualified name of your entity classes. Replace your.package.name.YourEntity with the actual class name. You will have a <mapping class="..."/> element for each entity.
  • show_sql: When set to true, Hibernate will print the generated SQL statements to the console. Very useful for debugging.

6. Entity Classes

Create your entity classes with appropriate annotations (e.g., @Entity, @Table, @Id, @Column) from the Jakarta Persistence API (JPA). These annotations map your Java classes to database tables.

Example Entity Class (src/main/java/your/package/name/YourEntity.java)

 package your.package.name;

            import jakarta.persistence.*;

            @Entity
            @Table(name = "your_table")
            public class YourEntity {

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

                @Column(name = "name")
                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;
                }
            } 

7. Setting up the SessionFactory

The SessionFactory is a factory for Session objects, which are used to interact with the database. You'll create a SessionFactory when your application starts and reuse it throughout its lifetime.

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

            public class HibernateUtil {

                private static final SessionFactory sessionFactory = buildSessionFactory();

                private static SessionFactory buildSessionFactory() {
                    try {
                        // Create the SessionFactory from hibernate.cfg.xml
                        return new Configuration().configure().buildSessionFactory();
                    }
                    catch (Throwable ex) {
                        // Make sure you log the exception, as it might be swallowed
                        System.err.println("Initial SessionFactory creation failed." + ex);
                        throw new ExceptionInInitializerError(ex);
                    }
                }

                public static SessionFactory getSessionFactory() {
                    return sessionFactory;
                }

                public static void shutdown() {
                    // Close caches and connection pools
                    getSessionFactory().close();
                }

            } 

8. Example Criteria API Usage

This is a simple example to show how to use Criteria API to query the database. More complex queries with joins, aggregations, and subqueries are possible.

 import your.package.name.YourEntity; // Import your entity class
            import org.hibernate.Session;
            import org.hibernate.SessionFactory;
            import org.hibernate.query.criteria.HibernateCriteriaBuilder;
            import jakarta.persistence.criteria.CriteriaQuery;
            import jakarta.persistence.criteria.Root;
            import java.util.List;


            public class CriteriaExample {

                public static void main(String[] args) {

                    SessionFactory sessionFactory = HibernateUtil.getSessionFactory();

                    try (Session session = sessionFactory.openSession()) {

                        HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
                        CriteriaQuery<YourEntity> cq = cb.createQuery(YourEntity.class);

                        Root<YourEntity> root = cq.from(YourEntity.class);
                        cq.select(root); // Select all columns from the entity

                        // Optional: Add a where clause. Example:
                        // cq.where(cb.equal(root.get("name"), "Example Name"));


                        List<YourEntity> results = session.createQuery(cq).getResultList();

                        for (YourEntity entity : results) {
                            System.out.println("Entity ID: " + entity.getId() + ", Name: " + entity.getName());
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        HibernateUtil.shutdown();
                    }
                }
            } 

9. Testing the Setup

Create a simple test class to verify that your configuration is working correctly. Insert some data into your database table and then use Hibernate to retrieve it using the Criteria API.

Troubleshooting

  • Database Connection Errors: Double-check your database URL, username, password, and driver class. Ensure your database server is running.
  • Missing Dependencies: Verify that all required dependencies are present in your pom.xml or build.gradle file. Redeploy the dependencies if necessary.
  • Hibernate Configuration Errors: Examine your hibernate.cfg.xml file for typos or incorrect settings.
  • Class Mapping Errors: Make sure your entity classes are correctly annotated and that the mappings in hibernate.cfg.xml are accurate.
  • SQL Dialect Issues: Ensure you're using the correct Hibernate dialect for your database.