Getting Started With Hibernate
Take your skills to the next level!
The Persistence Hub is the place to be for every Java developer. It gives you access to all my premium video courses, monthly Java Persistence News, monthly coding problems, and regular expert sessions.
Hibernate is a very popular implementation of the Java Persistence API (JPA) standard. It acts as an additional layer on top of JDBC and enables you to implement a database-independent persistence layer. Hibernate provides an object-relational mapping implementation that maps your database records to Java objects and generates the required SQL statements to replicate all operations to the database.
Let’s take a look at Hibernate’s key concepts and APIs so that you can start using it in your project.
Bootstrap Hibernate
You can use Hibernate in different technology stacks, and each of them offers its own bootstrapping solution. In this post, I will use JPA’s bootstrapping API. It’s easy to use and doesn’t require any changes if you need to switch to a different JPA implementation.
If you’re using Spring Boot or if you want to use Hibernate’s proprietary bootstrapping API, please take a look at the following posts:
- Hibernate Tips: How to bootstrap Hibernate with Spring Boot
- Hibernate Tips: How to use Hibernate’s native bootstrapping API
Required Dependencies
Before you can start using Hibernate, you need to add the hibernate-core.jar to your project. I’m using Hibernate 5.2.12.Final in this post.
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.2.12.Final</version> </dependency>
Configuration
After you’ve added the required dependencies, you need to tell Hibernate to which database you want to connect and which dialect it shall use.
Dialects are an important feature in Hibernate. They enable you to implement a database-independent persistence layer by transparently adapting your mappings and queries. So, make sure to always use the correct dialect for your database system and version.
The easiest way to configure Hibernate is to add a persistence.xml file to the META-INF directory.
Here you can see an example configuration which tells Hibernate to connect to a PostgreSQL database on localhost.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.1" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="my-persistence-unit"> <description>Hibernate Tips</description> <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL94Dialect" /> <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" /> <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/recipes" /> <property name="javax.persistence.jdbc.user" value="postgres" /> <property name="javax.persistence.jdbc.password" value="postgres" /> </properties> </persistence-unit> </persistence>
Let’s take a closer look at the different configuration elements.
I first define a persistence unit with the name my-persistence-unit. It defines a set of entities which represent the data contained in a data store and will be managed by an EntityManager.
The description element is optional. You can use it to provide additional information about the configured persistence unit.
Then you need to define your managed persistence classes. These can be entities, embeddables and mapped superclasses. You can do reference these classes in different ways. In this example, I set exclude-unlisted-classes to false. Hibernate will then scan all classes available in the current deployment unit to find entities, embeddabbles and mapped superclasses. You can also use jar-file elements to reference other jar files or class attributes to explicitly specify a set of managed persistence classes.
The property element hibernate.dialect specifies the database dialect which Hibernate shall use. In this case, I use the PostgreSQL94Dialect to connect to a PostgreSQL database in version 9.4
The remaining 4 javax.persistence.jdbc.* properties specify the required information to connect to my local PostgreSQL database as the user postgres.
That’s all you need to do to configure Hibernate. You now know the basic set of configuration parameters to setup Hibernate and to connect to a database.
JPA’s Bootstrapping API
Now it’s time to take a look at JPA’s bootstrapping API and to instantiate your first EntityManager.
Create an EntityManager
The EntityManager is probably the most important interface in JPA. It allows you to persist and remove entities, to find existing entities by their primary key and to create queries based on your entity mappings.
Instantiating an EntityManager is pretty simple. You just need to call the static method createEntityManagerFactory on the Persistence class with the name of your persistence unit. That is the same name as you used in your persistence.xml configuration. In the next step, you can use the EntityManagerFactory to create an EntityManager and use it to start a transaction.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-persistence-unit"); EntityManager em = emf.createEntityManager(); em.getTransaction().begin();
You don’t need to start the transaction after you’ve created your EntityManager. But please be aware, that Hibernate will start and commit a transaction for each database operation if there is no active transaction. In most situations, it’s better to start only one transaction. That reduces the load on the database and assures consistent reads for the duration of your transaction.
After you’ve done that, you can use the EntityManager to access your database by persisting, updating or removing entities. You can also create database-independent queries based on your entity model.
Close an EntityManager
After you’ve performed all database operations, you need to commit or rollback your transaction and close the EntityManager.
em.getTransaction().commit(); em.close();
Define Your Entities
You’ve now configured Hibernate and instantiated your EntityManager. The only thing that’s missing is a set of entities.
A Basic Entity Mapping
An entity is a non-final Java class with a set of attributes, a parameterless constructor, and an @Entity annotation. It should also follow the bean spec by providing getter and setter methods for every attribute.
By default, the entity gets mapped to a table with the same name, and each attribute gets mapped to a column of that table with the same name. At least one of the attributes has to map the primary key and be annotated with @Id.
Here you can see a Book entity which Hibernate maps to the book table with the columns id and title.
@Entity public class Book { @Id private Long id; private String title; public Long getId() { return this.id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } }
Customize the Mapping
Hibernate allows you to override the default mapping for the entity and all its attributes.
You can annotate your entity class with a @Table annotation to define the database table and schema to which the entity gets mapped.
And the @Column annotation enables you to customize the mapping of each attribute. E.g., you can use the name attribute to define the name of its database column, exclude it from update statements by setting the updatable attribute to false or reject null values with the nullable attribute.
@Entity public class Book { @Id @Column(name = "id", updatable = false, nullable = false) private Long id; ... }
Generate Primary Key Values
Most applications use a database sequence or an auto-increment column to generate unique primary key values. If you define it in your entity mapping, Hibernate automatically handles the required steps.
I explained the different options in great detail in How to generate primary keys with JPA and Hibernate. So, I keep this description short. You just need to annotate the primary key attribute with @GeneratedValue and specify which generation strategy Hibernate shall use. In this example, I use Hibernate’s default sequence to generate a primary key value.
@Entity public class Book { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) @Column(name = "id", updatable = false, nullable = false) private Long id; ... }
Special Attribute Mappings
Most attributes don’t require any additional mapping information because Hibernate gets all information from the specific class.
But if you’re using enumerations, java.util.Date or java.util.Calendar, you might want to customize the standard mapping.
Enumeration
Hibernate supports 2 options to map an enumeration to a database column. You can either use its String representation or its ordinal value. Hibernate uses the ordinal value by default. It’s an integer which represents the position of the specific value within the entity definition.
If you prefer the String representation, you can annotate the attribute with @Enumerated and set the EnumType to String.
@Entity public class Book { @Enumerated(EnumType.STRING) private AuthorStatus status; ... }
I explain this mapping in more details in Hibernate Tips: How to map an Enum to a database column.
Date and Calendar
One of the disadvantages of java.util.Date and java.util.Calendar is, that they always model a date with time information. But that’s quite often not what you want to persist in your database. In a lot of cases, you just want to store the date without any time or a time without a date.
The classes of Java 8’s Date and Time API fix this issue. JPA and Hibernate support them as basic types. If you have the choice, you should use this new API. It provides a lot of benefits, and the easier attribute mapping is just one of them.
If you need to use the old Date or Calendar class, you can customize the mapping with a Temporal annotation. It enables you to map the attribute to a java.sql.Date, java.sql.Time or java.sql.Timestamp.
@Entity public class Book { @Temporal(TemporalType.DATE) private Date publishingDate; ... }
Modelling Associations
In addition to the basic attributes, Hibernate also allows you to model the associations between your database tables as entity attributes. That makes them extremely easy to navigate in your business logic, and you can even use them in your JPQL queries.
JPA and Hibernate support the same associations as you use in your entity-relationship-model. You can map uni- and bidirectional one-to-one, one-to-many, many-to-one and many-to-many associations. I explain the different mappings in great details in Ultimate Guide – Association Mappings with JPA and Hibernate
And if you’re already familiar with the basic association mappings, you should take a look the following posts which describe best practices and common pitfalls:
- Best Practices for Many-To-One and One-To-Many Association Mappings
- Why you should avoid CascadeType.REMOVE for to-many associations and what to do instead
Inheritance
This is another advanced feature which you might not want to use if you implement your first application with Hibernate.
Inheritance is one of the key concepts in Java. So, it’s no surprise that a lot of developers use it in their domain model. Unfortunately, relational databases don’t support this concept. But JPA and Hibernate provide different mapping strategies that allow you to map your inheritance hierarchy to one or more database tables.
You can read more about the different strategies with their advantages and disadvantages in Complete Guide: Inheritance strategies with JPA and Hibernate.
Persist, Update or Remove an Entity
After you’ve defined your entity mappings, you can use them to create, update or remove a database record by persisting, updating or removing an entity. The EntityManager provides an easy to use API for it that doesn’t require you to write any SQL statements.
Persist a New Entity
You can persist a new entity to a new database record by instantiating an entity object and calling the persist method on the EntityManager. Here’s a simple example.
Author a = new Author(); a.setFirstName("Thorben"); a.setLastName("Janssen"); em.persist(a);
Update an Existing Entity
Updating an existing entity is even more comfortable. You just need to get an entity from the database and change any of its attributes. Before you execute the next query or when you commit the transaction, Hibernate will perform a dirty check on all managed entities to identify any changes. It then generates and executes the required SQL UPDATE statements.
Author a = em.find(Author.class, 1L); a.setFirstName("Thorben");
The find method of the EntityManager gets the entity with the given primary key from the database. I explain it in more details in the following section.
Remove an Existing Entity
And you can remove an entity by calling the remove method on the EntityManager. Hibernate will then generate and execute the required SQL statement to remove the entity.
Author a = em.find(Author.class, 1L); em.remove(a);
Get an Entity from the Database
JPA and Hibernate provide multiple options to get an entity from the database. You can use the EntityManager to get an entity by its primary key, or you can define complex queries based on your entity model, or you can execute a native SQL query.
Let’s start with the EntityManager.
Find by Primary Key
If you just need to get an entity by its primary key, you can use the find method of your EntityManager.
Author a = em.find(Author.class, 1L);
As you can see in the code snippet, you just need to provide the class of your entity and its primary key. Hibernate then uses the mapping information of the entity to generate an SQL SELECT statement. It selects all mapped attributes of the record with the given primary key from the table mapped by the entity.
JPQL
You most often need to select multiple records or you want to filter them by attributes which are not part of the primary key. You can do that with a JPQL query.
JPQL is a query language similar to, but not as powerful as SQL. It enables to define queries based on your entity model instead of the underlying database tables. You can learn more about it in my Ultimate Guide to JPQL Queries with JPA and Hibernate.
Native SQL Queries
If your query is too complex for JPQL or if you need to use any database-specific features, you can use a native SQL query. It allows you to execute plain SQL statements within the context of your current transaction and persistence context. I explain them in great details in Native Queries – How to call native SQL queries with JPA.
Summary
Hibernate provides an easy to use and powerful option to persist data in a relational database. It acts as a layer on top of JDBC and maps your database records to Java objects, called entities. You can use these entities to read, persist, update and remove database records. Based on the operations you perform on the EntityManager and your entities, Hibernate generates and executes the required SQL statements.
Good day Thorben
I hope that this message finds you well.
Thorben, I first want to thank you for excellent information you make available regarding Hibernate and JPA; it is most appreciated.
I am relatively new to the Java ORM way of doing DB ‘things’ (my main background is in c/c++ and python).
I have the following questions, and would really appreciate it if you could answer them (I will try and keep the answers to yes/no answers, as to not waste your time 😉 )
1. Most current examples on the net use JPA together with a persistence.xml file. Very few use hibernate directly by not having any persistence.xml file, but only the hibernate.cfg file. Is it thus current best practice to use only JPA with the persistence.xml file, even when running on Wildfly 11?
2. If point 1 above is yes, the following question then becomes: Is it possible to use Hibernate specific annotations like @Immutable and other Hibernate specific ‘very cool time saving’ features, mixed with JPA (in the same model entity declaration) and only having a persistence.xml file and no hibernate.cfg file?
3. You mentioned in a recent article (thanks for these articles friend) that one should explicitly instantiate the EM transaction. My understanding of what you meant with this was: ‘whenever a new EM is created, and one wants to use it for DB things, one should always before issuing any DDL or DML via JPA start the transaction explicitly. If this is not done each JPA instruction using this EM instance will initiate its own transaction with the DB. What you did not mean by this is, that the app as a whole, must when it starts up, create an EM instance and start a transaction to be used by all JPA code’?
Thanks in advance for taking the time to answer the above.
Kind regards,
George
Hi George,
1. Hibernate implements the JPA specification. So, you can use both options and both are OK. Here you can read more about Hibernate’s bootstrapping approach.
If you use a persistence.xml file (the JPA bootstrapping approach) and if you don’t use any other Hibernate-specific features, you can replace Hibernate with other JPA implementations, like Eclipse Link or OpenJPA.
2. As long as you use Hibernate as your JPA implementation, you can use all proprietary Hibernate and all standard JPA features. If you use the JPA bootstrapping approach, you might need to unwrap the EntityManager and EntityManagerFactory to use some Hibernate-specific features: How to access Hibernate’s APIs from JPA
3. You need to decide for each use case, which operations should be performed within one transaction. Keep in mind that a transaction is an atomic operation.
In most cases, a transaction gets started when the processing of a request starts and commits after all processing steps got completed.
Regards,
Thorben
Thanks very useful article, Keep posting these awesome tutorials.
Thanks 🙂