Hibernate and JPA 3 CRUD example

JPA 3 CRUD example

To use version 3 of the Java Persistence API to create, retrieve, update and delete records (CRUD) from a JDBC compliant database, follow these steps:

  1. Create a Java project with the appropriate Maven or Gradle coordinates.
  2. Add a fully configured persistence.xml file to your Java project’s META-INF folder.
  3. Annotate a JavaBean as a persistent entity with @Entity and @Id annotations.
  4. Invoke the JPA EntityManager’s persist, find and delete methods within a transaction.

Hibernate and JPA Maven POM file

At a minimum, a Java project that leverages the Java Persistence API needs the following:

  • An underlying JPA 3 implementation such as Hibernate 6.2.2 (Which supports JPA 3.1).
  • JDBC drivers that allows your Java application to connect to your target database.

MySQL remains one of the most popular, open-source databases in the Java community, while Hibernate is the most popular JPA 3 implementation.

The required Maven POM properties and dependencies that make JPA 3.1, Hibernate 6.2.2 and MySQL JDBC drivers available to a Java project are as follows:

<properties>
  <maven.compiler.target>17</maven.compiler.target>
  <maven.compiler.source>17</maven.compiler.source>
</properties>

<dependencies>
  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>6.2.2.Final</version>
    <scope>compile</scope>
  </dependency>

  <dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.0.33</version>
  </dependency>
</dependencies>

Notice that the scope parameter of the Hibernate libraries which support JPA 3. You will encounter persistence.xml errors at development time if the scope property is configured incorrectly.

JPA 3 persistence.xml file

Every Java project that uses JPA 3 must include a file named persistence.xml in a folder named META-INF.

A simple persistence.xml file includes the following elements:

  • Boilerplate version, namespace and schema location data.
  • The name of the persistence unit.
  • Database connection properties including the driver name, url and credentials.
  • Optional properties for runtime customization.

The following example is a JPA 3 persistence.xml file that connects to a MySQL database and includes optional Hibernate properties to format and show SQL queries in the log files.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence version="3.0" xmlns="https://jakarta.ee/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence 
             https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd">

  <persistence-unit name="jpa-tutorial"> 
    <properties>
      <property name="jakarta.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver" />
      <property name="jakarta.persistence.jdbc.url"    value="jdbc:mysql://localhost:3306/hibernate_examples" />
      <property name="jakarta.persistence.jdbc.user"   value="root" />
      <property name="jakarta.persistence.jdbc.password" value="password" />
      <property name="jakarta.persistence.schema-generation.database.action" value="create" />
      <property name="hibernate.show_sqlvalue="true" />
      <property name="hibernate.format_sqlvalue="true" />
    </properties>
  </persistence-unit>
</persistence>

The JPA 3 Entity

With Hibernate and JPA 3.x configured, it’s time to create a JavaBean and decorate it with annotations that explain to the Java Persistence API how to save the JavaBean to the database.

For this example we will create a simple Player class that has the following properties:

  • A type Long to represent the entity’s primary key.
  • A type String to represent the player’s password.

The decorated JPA entity looks as follows:

package com.mcnz.jpa.examples;
import jakarta.persistence.*;

  @Entity
  public class Player {

  @Id @GeneratedValue
  private Long id;
  private String password;

  public String getPassword() { return password; }
  public void setPassword(String password) { 
    this.password = password;
  }

}

The following JPA 3 annotations added to the JavaBean assist in database persistence:

  1. @Entity to indicate the Player class should be mapped and persisted to a database table named Player.
  2. @Id to indicate the Long property named id should be used as the primary key.
  3. @GeneratedValue to instruct the database to create a new, unique primary key if the Entity does not have one.

In JPA 3.1, a new UUID annotation is used to create unique primary keys, which is gaining popularity in the industry.

The JPA CRUD class

With the JavaBean decorated with Java Persistence API annotations, and the Java project configured to support JPA 3 and Hibernate, the last step is to create a class that performs the four CRUD operations.

We will create a class named JpaCrudExample to perform the CRUD operations. It will have the standards Java main method along with four other methods to support JPA CRUD operations, namely:

  1. JpaCrudExample.createRecord()
  2. JpaCrudExample.retrieveRecord()
  3. JpaCrudExample.updateRecord()
  4. JpaCrudExample.deleteRecord()
JPA CRUD operations

The four basic CRUD operations.

 

Here is the skeleton code for the CRUD application we will incrementally build over the course of this tutorial.

package com.mcnz.jpa.examples;

import java.util.*;
import javax.persistence.*;

public class JpaCrudExample {

  public static void main(String[] args) throws Exception {
    JpaCrudExample.createRecord();
    JpaCrudExample.retrieveRecord();
    JpaCrudExample.updateRecord();
    JpaCrudExample.deleteRecord();
  }

  public static void createRecord() { }
  public static void retrieveRecord() { }
  public static void updateRecord() { }
  public static void deleteRecord() { }

}

The JPA create operation

The steps to perform any database operation with Hibernate and JPA always follow a predictable pattern:

  • The EntityManager is obtained through the JPA Persistence and EntityManagerFactory classes.
  • A transaction starts.
  • A JPA annotated Java component interacts with the EntityManager.
  • A commit occurs, and the state of the Entity is persisted to the database.

Here is the implementation of the create portion of the JPA CRUD example:

public static void createRecord() {
 EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa-tutorial");
 EntityManager entityManager = emf.createEntityManager();

 entityManager.getTransaction().begin();

 Player p = new Player();
 p.setPassword("my-password");
 entityManager.persist(p);

 entityManager.getTransaction().commit();
}

The boilerplate code used to access the EntityManager and manage transactions is hidden from the developer with a framework such as Spring Boot or CDI from JakartaEE. However, it is valuable to know what methods are actually being invoked behind the scenes when you use Hibernate and JPA 3.

The retrieve CRUD operation in JPA

When the above code runs, it creates a new record in the database, likely with a primary key of 1 if this is the first time you have written to the database. To retrieve this record, we simply set the primary key to the value of 1 and pass it to the EntityManager’s find method. The underlying database record is mapped to the Player class and an instance of the player is returned to our program.

public static void retrieveRecord() {
 EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa-tutorial");
 EntityManager entityManager = emf.createEntityManager();

 entityManager.getTransaction().begin();
 Long key = Long.valueOf(1);
 Player p = entityManager.find(Player.class, key);
 System.out.println(p.getPassword());

 entityManager.getTransaction().commit();
}

When this code runs, the password for the record with the primary key of 1 prints to the console.

The update CRUD operation in JPA

To update an entity, all you need to do is retrieve it from the MySQL database and change some of its instance variables before the transaction commits. So the following code, which is only one line of code different from the retrieveRecord method, updates the name of record 1 from Julie to Karen.

public static void retrieveRecord() {
 EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa-tutorial");
 EntityManager entityManager = emf.createEntityManager();

 entityManager.getTransaction().begin();
 Long key = Long.valueOf(2);
 Player p = entityManager.find(Player.class, key);

 p.setPassword("123def");

 entityManager.getTransaction().commit();
}

When this code runs, the password updates to 123def.

The CRUD delete operation in JPA

To delete a record from the database, simply load the record of interest and then pass it to the remove method of the EntityManager.

Here we pull the record with the primary key of 1 from the database and permanently delete it:

public static void deleteRecord() {

 EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa-tutorial");
 EntityManager entityManager = emf.createEntityManager();

 entityManager.getTransaction().begin();
 Long key = Long.valueOf(2);
 Player p = entityManager.find(Player.class, key);
 entityManager.remove(p);

 entityManager.getTransaction().commit();

}

More on Hibernate and JPA

And that is the essence of how to perform the Hibernate CRUD operations using the latest version of the Java Persistence API.

There are further nuances that each of these methods could employ. In future JPA tutorials we will look at updating a transient entity, or using the JPA Criteria API to query the database. NamedQueries and JPQL are other ways to query a database and retrieve records. But when you’re learning a technology, starting off simple is best, and this JpaCrudExample class covers the basics.

You can find the source code for this example on GitHub.