Introduction
This is the first part of a 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.
Quote:
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 our pom.xml
file:
<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
:
="1.0"="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
:
<code class="language-java" data-lang="java"><span class="o"><font color="#000000">@Entity
public class Person implements Serializable {
@Id
@GeneratedValue
private Long id;
private String firstName;
private String lastName;
private LocalDate dateOfBirth;
private LocalDateTime createdDate;
private LocalDateTime modifiedDate;
}</font></span></code>
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
:
<code class="language-java" data-lang="java"><span class="o"><font color="#000000">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();
}
}</font></span></code>
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.
Quote:
NOTE
In our persistence.xml
file we set a property javax.persistence.schema-generation.database.action
to drop-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 recommended approach.
file: src/main/java/com/tutorial/Application.java
:
public class Application {
public static void main(String[] args) {
Server server = null;
PersonRepositoryImpl repository = null;
try {
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();
repository.create(person);
person = null;
person = repository.read(1L);
person.setModifiedDate(LocalDateTime.now());
person.setFirstName("Jane");
repository.update(person);
person = null;
person = repository.read(1L);
repository.delete(person);
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:
<span class="o"><font color="#000000">server = Server.createTcpServer().start();</font></span>
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 .