CRUD Operations with Hibernate and JPA
Hibernate ORM (Hibernate in short) is an object-relational mapping tool for the Java programming language. It provides a framework for mapping an object-oriented domain model to a relational database.
The Java Persistence API (JPA) provides Java developers with an object/relational mapping facility for managing relational data in Java applications.
Introduction
This is the first part of a series of posts focused on
Hibernate and JPA. In this tutorial we are going to look at the basics of Hibernate and JPA.
The relationship between Hibernate and JPA is that Hibernate is an implementation of the JPA specification.
JPA is a specification. Hibernate is its implementation.
In this post we will create a simple project that performs CRUD operations to demonstrates the powerful capabilities of JPA using Hibernate.
Prerequisites
Project Structure
We will create a Maven project using the standard directory structure as illustrated below:
.
|__src/
| |__main/
| | |__java/
| | | |__com/
| | | | |__tutorial/
| | | | | |__Application.java
| | | | | |__entity/
| | | | | | |__Person.java
| | | | | |__repository/
| | | | | | |__PersonRepository.java
| | | | | | |__PersonRepositoryImpl.java
| | |__resources/
| | | |__META-INF/
| | | | |__persistence.xml
| | | |__log4j2.properties
|__pom.xml
Setting up Dependencies
Getting the dependencies to start using Hibernate and JPA is just a matter of adding the following to the pom.xml file:
file:
pom.xml
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.6.Final</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.193</version>
</dependency>
</dependencies>With this done, we can start writing some code.
Setting up JPA
We will setup our peristence unit for JPA bootstraping. A persistence.xml file defines a persistence unit. The persistence.xml
file is located in the META-INF directory of the root of the persistence unit. It may be used to specify managed persistence
classes included in the persistence unit, object/relational mapping information for those classes, scripts for use in schema
generation and the bulk loading of data, and other configuration information for the persistence unit and for the entity manager(s)
and entity manager factory for the persistence unit.
The object/relational mapping information can take the form of annotations on the managed persistence classes included in the
persistence unit, an orm.xml file contained in the META-INF directory of the root of the persistence unit, one or more XML
files on the classpath and referenced from the persistence.xml file, or a combination of these.
For our simple use case we will create a persistence.xml file.
file:
src/main/resources/META-INF/persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="com.juliuskrah.tutorial"
transaction-type="RESOURCE_LOCAL">
<class>com.tutorial.entity.Person</class>
<properties>
<property name="javax.persistence.schema-generation.database.action"
value="drop-and-create" />
<property name="javax.persistence.provider"
value="org.hibernate.jpa.HibernatePersistenceProvider" />
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test" />
<property name="javax.persistence.jdbc.user" value="sa" />
<property name="javax.persistence.jdbc.password" value="" />
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
</properties>
</persistence-unit>
</persistence>From the above snippet we have specified the persistence unit name as com.juliuskrah.tutorial. This is the value we will use to create
the EntityManagerFactory.
In the same snippet we have specified the Entity class (Person) to be managed by the
EntityManager
We have also specified the properties Hibernate will use to connect to the database. The most important property here is the
javax.persistence.provider which tells JPA which implementation to use (in our case Hibernate).
The next thing to do is create the Entity class which maps to a database table.
file:
src/main/java/com/tutorial/entity/Person.java
@Entity
public class Person implements Serializable {
@Id
@GeneratedValue
private Long id;
private String firstName;
private String lastName;
// As of Hibernate 5.2 LocalDate is automatically mapped to sql type Date
private LocalDate dateOfBirth;
// As of Hibernate 5.2 LocalDateTime is automatically mapped to sql type Timestamp
private LocalDateTime createdDate;
private LocalDateTime modifiedDate;
// Getters and Setters omitted for brevity
}The @Entity annotation on the Person class is a mapping metadata that tells JPA to map the
fields of the Person object to the columns in the PERSON table. For example the firstName field of type String is mapped to
FIRSTNAME column of type varchar.
The @Id annotation on id field marks it as the primary key of the PERSON table. The @GeneratedValue annotation defines a
strategy for generating primary key values (e.g. auto-increment).
Managing Entities
With our entity set up we need a way to manage its lifecycle. Entities are managed by the entity manager, which is represented by
javax.persistence.EntityManager instances. Each EntityManager instance is associated with a persistence context: a set of
managed entity instances that exist in a particular data store. A persistence context defines the scope under which particular
entity instances are created, persisted, and removed. The EntityManager interface defines the methods that are used to interact
with the persistence context.
The EntityManager API creates and removes persistent entity instances, finds entities by the entity’s primary key, and allows
queries to be run on entities.
The JPA specification defines two ways of managing entities: Container-Managed Entity Managers and Application-Managed Entity Managers.
This is beyond the scope of this tutorial. For the purposes of simplification, we will use an Application-Managed Entity Manager.
We will create a PersonRepository to facilitate our CRUD operations.
file:
src/main/java/com/tutorial/repository/PersonRepositoryImpl.java
public class PersonRepositoryImpl implements PersonRepository {
private EntityManagerFactory emf = Persistence.createEntityManagerFactory("com.juliuskrah.tutorial");
private EntityManager em;
public PersonRepositoryImpl() {
em = emf.createEntityManager();
}
@Override
public Person create(Person person) {
em.getTransaction().begin();
em.persist(person);
em.getTransaction().commit();
return person;
}
@Override
public Person read(Long id) {
em.getTransaction().begin();
Person person = em.find(Person.class, id);
em.getTransaction().commit();
return person;
}
@Override
public Person update(Person person) {
em.getTransaction().begin();
person = em.merge(person);
em.getTransaction().commit();
return person;
}
@Override
public void delete(Person person) {
em.getTransaction().begin();
em.remove(person);
em.getTransaction().commit();
}
@Override
public void close() {
emf.close();
}
}At the top of the repository class is:
private EntityManagerFactory emf = Persistence.createEntityManagerFactory("com.juliuskrah.tutorial");The createEntityManagerFactory method takes as parameter persistence unit name which you will recall was set in our persistence.xml
file as com.juliuskrah.tutorial. The EntityManagerFactory is a factory method used to create instances
of an EntityManager. The PersonRepository contains methods to perform the CRUD operations.
Running the Application
We will create a main class to test our CRUD methods.
NOTE
In ourpersistence.xmlfile we set a propertyjavax.persistence.schema-generation.database.actiontodrop-and-create. This instructs Hibernate to drop and recreate the database everytime the application is run. Please don’t use this setting in a production environment. In the third part of this series we will look at database migration which is a reco
file:
src/main/java/com/tutorial/Application.java
public class Application {
public static void main(String[] args) {
Server server = null;
PersonRepositoryImpl repository = null;
try {
// Start H2 embedded database
server = Server.createTcpServer().start();
Person person = new Person();
person.setFirstName("John");
person.setLastName("Doe");
person.setCreatedDate(LocalDateTime.now());
person.setDateOfBirth(LocalDate.of(1993, Month.APRIL, 12));
repository = new PersonRepositoryImpl();
// Create person
repository.create(person);
person = null;
// Hibernate creates a person proxy with an increment id of 1
person = repository.read(1L);
person.setModifiedDate(LocalDateTime.now());
person.setFirstName("Jane");
// Update person record
repository.update(person);
person = null;
// Read updated record
person = repository.read(1L);
// Delete person
repository.delete(person);
// This will return null
person = repository.read(1L);
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (repository != null)
repository.close();
if (server != null)
server.stop();
}
}
}The first thing to do here is start the H2 embedded database server:
server = Server.createTcpServer().start();Once the database server is up Hibernate can perform DDL and DML operations on the embedded
database server. We do a cleanup of resources when our application exits by calling server.stop() and repository.close() methods.
Conclusion
In this post we were briefly introduced to JPA and its Hibernate implementation. We saw how to perform basic CRUD operations using
the JPA APIs.
As usual you can find the full example to this guide in the github repository. Until the next post, keep doing cool things
.