A Hibernate Introduction – Persisting Java Objects the Easy Way
When it comes to object persistence, the JPA/Hibernate tandem is one of those gems you’ll never want to leave behind once you get used to it. Thorben Janssen has written a great introduction to the subject, listing five good reasons why to use it. (It’s not a prerequisite for this article but I nevertheless strongly encourage you to give it a read.) In this tutorial we will focus on Hibernate’s core feature: persisting object graphs.
Why Do We Need Automated Persistence? – The Case for Hibernate
Let’s first answer the question why we would even use a framework to persist application data. Is JDBC (Java Database Connectivity) not good enough for us?
Well, if we look at the data held by our applications, we’ll usually see a complex network of objects, also known as the object graph, that we want to write to and read from some store, usually a relational database. Unfortunately, the persistence process is far from straightforward. Translating entire objects graphs to plain tabular data is everything but simple and storing objects using plain JDBC is painful and cumbersome, as the standard exposes a low-level API. You know, connecting to a database and writing SQL queries from scratch is all well and fine. But be honest with yourself: Do you want to do that over and over again? If you’re anything like me, you don’t.
And this is where Hibernate comes in. Besides a lot of other things, it allows us to create the objects that hold our data, called entities, as we are used to and automates the process of reading and writing them.
Let’s get started!
Developing a Basic Java Application – Getting Started Using Hibernate
A nice way to start pulling the reins of Hibernate is to create a simple example. To do so, I’m very going to develop a naive Java application, whose functionality will boil down to performing CRUD operations on some user objects. In turn, the objects will be persisted, fetched, updated and removed from a MySQL database.
To get things rolling as expected, we first need to grab the required Hibernate ORM JARs, along with the corresponding MySQL Java Connector. Maven will do that nicely for us, so we can focus on coding, rather than on dealing with dependency issues.
Here’s my POM file:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.electricalweb.hibernatepplication</groupId>
<artifactId>hibernateapplication</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.2.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.3</version>
</dependency>
</dependencies>
</project>
In this particular case, I’ll be using IntelliJ IDEA as my personal IDE, but the project can be easily created in NetBeans, Eclipse, or the IDE of your choice.
With the POM file under the way, here’s how this sample application will be laid out:
As shown above, the application’s skeleton is structured in only three packages: com.electricalweb.entities
, which contains the domain class that models users, com.electricalweb.daos
, which houses a basic user DAO class, and lastly com.electricalweb.application
, which is the application’s entry point. Since the primary goal is to persist user objects in MySQL, let’s define the User
domain class.
Defining a Persistable Entity – Hibernate’s Core Feature
To keep things simple, the domain class will be extremely anemic, having only a couple of private properties, name
and email
, along with a parameterized constructor and the typical setters/getters. Here’s the class in question:
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private String email;
public User() {}
public User(String name, String email) {
this.setName(name);
this.setEmail(email);
}
// getters and setters for name and email
}
Yes, you’re right. The above class is just a lightweight data container with no behavior attached to it (feel free to judge me for committing this cardinal sin). The only detail worth to stress here is that in order to make it persistable for Hibernate (or any other JPA implementation) it’s been marked with an @Entity
annotation. In addition, Hibernate needs to know how to handle the entities’ primary keys.
To tackle this, the @Id
and @GeneratedValue(strategy = GenerationType.AUTO)
annotations instruct Hibernate to automatically generate an ID for each user entity, which will be mapped to the primary key of the corresponding database entry. Finally, the @Table(name = "users")
annotation tells Hibernate to map instances of the class to rows in a users
table.
With the domain class already defined, the final step to take in order to get the sample application up and running is create a configuration file, not surprisingly called persistence.xml
, which will contain all the data required for connecting to the database and mapping entities to the database.
Accessing the Database – Creating a Persistence Unit
Unquestionably, the most common way of setting up the connection parameters to the database, along with additional Hibernate proprietary options, is by defining the aforementioned persistence.xml
file. The process is pretty boring but extremely straightforward, trust me.
Here’s how a typical version of this file might look:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="user-unit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.electricalweb.entities.User</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/usersdb" />
<property name="javax.persistence.jdbc.user" value="username" />
<property name="javax.persistence.jdbc.password" value="password" />
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
As you can see, the file is easily readable from top to bottom. It just sets up a few database connection parameters, which you should be familiar with if you’ve worked with JDBC before, including the database URL, the JDBC driver, the database username and the password (make sure to provide the right values for your own database server).
Additionally, and this is by far the most interesting segment of the file, it defines a persistence-unit, that is a set of persistence entities (in this case just users, but it could be multiple entities wrapped inside several <class>
tags) which are handled by a JPA entity manager. Considering that in this case Hibernate is the chosen JPA implementation, the entities will be managed by Hibernate’s entity manager.
If you’re like me, at this point you’ll be eager to see how to use the entity manager for performing CRUD operations on a few user entities in a snap. Just relax. The next section covers the process in depth.
Performing CRUD Operations on Entities – Working with Hibernate’s Entity Manager
In a nutshell, running CRUD operations on user objects is much easier than one might think. The entire process just boils down to spawning the EntityManager
and consuming its API. It’s really that easy.
For instance, we could use the application’s entry point, which is a simple class with a plain static main
method, and call the entity manager in the following way:
EntityManager entityManager = Persistence
.createEntityManagerFactory("user-unit")
.createEntityManager();
EntityTransaction entityTransaction = entityManager.getTransaction();
/* Persist a User entity */
entityTransaction.begin();
User user = new User("Alejandro", "alejandro@domain.com");
entityManager.persist(user);
entityTransaction.commit();
/* Fetch a User entity */
entityManager.find(User.class, 1);
/* Update a User entity */
entityTransaction.begin();
User user = entityManager.find(User.class, 1);
user.setName("Alex");
user.setEmail("alex@domain.com");
entityManager.merge(user);
entityTransaction.commit();
/* Remove a User entity */
entityTransaction.begin();
User user = entityManager.find(User.class, 1);
entityManager.remove(user);
entityTransaction.commit();
entityManager.close();
Quite simple, isn’t it? Saving, fetching, updating and deleting user entities with a non-managed entity manager is a no-brainer process that can be mastered literally within minutes. The procedure is limited to first getting the manager via an EntityManagerFactory
, then grabbing an instance of the EntityTransaction
class, and finally calling the desired method of the entity manager.
The above code snippet assumes there’s a MySQL database table called users
already defined, together with a MySQL instance running on a local server. So, make sure to set up that before testing the sample application.
At this point, you hopefully learned the basics behind persisting single entities with Hibernate. So, what comes up next? Well, a lot actually. As you may have noticed, I left out of the picture persisting entities that have a specific relationship with other entities (yes, the relational aspect). I did this deliberately, in order to keep the whole learning process free from additional, unnecessary complexities. After all, this is just an introduction to getting started using Hibernate.
Still, I’d like to polish the demo a little bit, as in its current state it looks pretty monolithic and its execution flow can’t be controlled through a user interface.
Taking this into consideration, what I’ll do next will be defining a DAO class, which will encapsulate the handling of the entity manager and the entity transaction behind the fences of a declarative API. Finally, you’ll see how to use the class for selectively executing CRUD methods on user entities, based on options entered in the Java console.
Adding a Nice API – Defining a DAO Class
Believe me. I’m not a blind worshiper of design patterns, using them everywhere without having strong reasons to do so. In this case, however, it’s worth to appeal to the functionality provided by the DAO pattern, so you can give the previous example a try without much hassle.
In a nutshell, all that the following UserDao
class does is to define an easily consumable API, which allows to execute CRUD methods on a given user entity. Here’s how the class looks:
public class UserDao {
private EntityManager entityManager;
private EntityTransaction entityTransaction;
public UserDao(EntityManager entityManager) {
this.entityManager = entityManager;
this.entityTransaction = this.entityManager.getTransaction();
}
public void persist(String name, String email) {
beginTransaction();
User user = new User(name, email);
entityManager.persist(user);
commitTransaction();
}
public User find(int id) {
return entityManager.find(User.class, id);
}
public void update(int id, String name, String email) {
beginTransaction();
User user = entityManager.find(User.class, id);
user.setName(name);
user.setEmail(email);
entityManager.merge(user);
commitTransaction();
}
public void remove(int id) {
beginTransaction();
User user = entityManager.find(User.class, id);
entityManager.remove(user);
commitTransaction();
}
private void beginTransaction() {
try {
entityTransaction.begin();
} catch (IllegalStateException e) {
rollbackTransaction();
}
}
private void commitTransaction() {
try {
entityTransaction.commit();
entityManager.close();
} catch (IllegalStateException e) {
rollbackTransaction();
}
}
private void rollbackTransaction() {
try {
entityTransaction.rollback();
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
}
Honestly, this additional layer of abstraction (and complexity) wouldn’t make much sense per see if I wouldn’t show you how to use the class in a concrete case. So, check the following snippet, which exploits the benefits of dependency injection.
public class HibernateApplication {
private final UserDao userDao;
private final BufferedReader userInputReader;
public static void main(String[] args) throws Exception {
EntityManager entityManager = Persistence
.createEntityManagerFactory("user-unit")
.createEntityManager();
UserDao userDao = new UserDao(entityManager);
BufferedReader userInputReader =
new BufferedReader(new InputStreamReader(System.in));
new HibernateApplication(userDao, userInputReader).run();
}
public HibernateApplication(UserDao userDao, BufferedReader userInputReader) {
this.userDao = userDao;
this.userInputReader = userInputReader;
}
private void run() throws IOException {
System.out.println("Enter an option: "
+ "1) Insert a new user. "
+ "2) Find a user. "
+ "3) Edit a user. "
+ "4) Delete a user.");
int option = Integer.parseInt(userInputReader.readLine());
switch (option) {
case 1:
persistNewUser();
break;
case 2:
fetchExistingUser();
break;
case 3:
updateExistingUser();
break;
case 4:
removeExistingUser();
break;
}
}
private void persistNewUser() throws IOException {
String name = requestStringInput("the name of the user");
String email = requestStringInput("the email of the user");
userDao.persist(name, email);
}
private void fetchExistingUser() throws IOException {
int id = requestIntegerInput("the user ID");
User user = userDao.find(id);
System.out.print("Name : " + user.getName() + " Email : " + user.getEmail());
}
private void updateExistingUser() throws IOException {
int id = requestIntegerInput("the user ID");
String name = requestStringInput("the name of the user");
String email = requestStringInput("the email of the user");
userDao.update(id, name, email);
}
private void removeExistingUser() throws IOException {
int id = requestIntegerInput("the user ID");
userDao.remove(id);
}
private String requestStringInput(String request) throws IOException {
System.out.printf("Enter %s: ", request);
return userInputReader.readLine();
}
private int requestIntegerInput(String request) throws IOException {
System.out.printf("Enter %s: ", request);
return Integer.parseInt(userInputReader.readLine());
}
}
As shown above, the HibernateAplication
class accepts a range of four different values entered in the console. According to the given input, it uses the DAO for running a specific CRUD operation on a user entity. Needless to say the logic of this revamped example is self-explanatory, so any further analysis would be redundant. Thus, make sure to give it a try on your own development platform and feel free to twist it at will to suit your personal needs.
Final Thoughts
In this tutorial, I walked you through a concise guide on using Hibernate for persisting entities in a database. Naturally, the framework is a powerful beast that offers a lot more than just plain ORM functionality, including full-text search capabilities, Geolocation, Domain Models validation and much more. For obvious reasons, covering all these features in just one article would be not only impossible, but impractical. Of course, if you want to test the sample application and rework it at will, feel free to clone the repository from GitLab (https://gitlab.com/alejandrogervasio/hibernate.git)
Anyway, if you’re a newcomer to Hibernate and want to start sinking your teeth in it right away, this guide hopefully will be a good starting point. Feel free to drop me your comments. I’ll try to reply in a timely fashion. See you in the next article!