Skip to content

2. Introduction to Hibernate

1. Hibernate

![Hibernate](./img/Hibernate.png){width=85%}

Hibernate is an ORM framework for Java, which facilitates the mapping of attributes between a relational database and the object model of our application through XML files or annotations in the entity beans. It is free software distributed under the GPL 2.0 license, so it can be used in commercial applications.

The main function of Hibernate will be to offer the programmer the tools to detail his data model and the relationships between them, so that it is the ORM itself that interacts with the database, while the developer is dedicated to manipulating objects.

In addition, it offers a query language, called HQL (Hibernate Query Language), so that it is the ORM itself that translates this language to that of each database engine, thus maintaining portability at the expense of a slight increase in time of execution.

![Hibernate](./img/Hibernate-arquitecture.png){width=85%}

When objects are created, they are volatile or transient (will be destructed when the application finish). When we want to store them with Hibernate, they are tracked with one mechanism called Session. The objects loaded from databases are tracked too. If we want, we could finish the tracking, deleting the object when we do not need more.

Moreover, a query language is provided, HQL or Hibernate Query Language, based on OQL. The underlying part of the session, as can be seen, allows the use of various technologies, including JDBC to connect to the necessary DBMS.

2. Configuration

Hibernate, as a good framework does not need an installation, because is integrated in our project as libraries. We could choose to install lots of jar libraries, but is pretty good to use a package manager to automate this task. The building process of the project will be easier at the end.

We will use Maven as package manager.

3. Dependencies.

In our projects two basic tools will be used: Hibernate and a driver to connect to the chosen database. Obviously, we need to add the dependencies to the package manager. In maven, the dependencies are included in the Pom.xml file, in the root folder of our project. Inside de <dependencies> tag you must add:

XML
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.27</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.6.3.Final</version>
</dependency>

If you have chosen Gradle as package manager, your build.gradle set as:

Bash
1
2
3
4
5
6
7
dependencies {
    // https://mvnrepository.com/artifact/mysql/mysql-connector-java
    implementation group: 'mysql', name: 'mysql-connector-java', version: '8.0.27'

    // https://mvnrepository.com/artifact/org.hibernate/hibernate-core
    implementation group: 'org.hibernate', name: 'hibernate-core', version: '5.6.3.Final'
}

Remember

Remember that you can find the packages in https://mvnrepository.com/repos/central

4. Project structure

Once we have added dependencies, we must create a project structure to organize our classes, in order to separate the logic program. We will show a brief description, getting a deeper explanation later.

4.1. Beans

Beans are the evolution of POJOs, that we have studied in previous units. Remember that these classes are common objects, out of inheritance trees and without implement any interfaces. They are used to storing information about one concept (I need a Car...create a Car).

As an extension of POJO's, Beans appear, without restrictions in attributes, constructors and inheritance. They have some restrictions:

  • Its attributes must be private (encapsulation).
  • They must implement serializable interface.
  • They must have public getters and setters.
  • They must implement a generic constructor (without arguments).

Remember

The serialization runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization.

If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender's class, then deserialization will result in an InvalidClassException. A serializable class can declare its own serialVersionUID explicitly by declaring a field named serialVersionUID that must be static, final, and of type long:

Java
static final long serialVersionUID = 137L;

In summary, Beans are data access components, and they represent entities in our application. It is a good idea to create our Beans in the same package, normally called Model.

Tip

Remember Lombok library? It is very useful to create our beans with only a few lines of code.

4.2. Mapping files

Once entities are created, we need to map each entity. Each mapping sets the references between beans and tables, attributes and columns, in order to establish a perfect match between them.

First option will be creating mapping files, with the syntax (in XML) between classes and tables. If the bean is called Car, the mapping file should be Car.hbm.xml:

  • hbm is for hibernate mapping
  • xml because syntax is in XML specification.

We will study mapping files in next sections.

4.3. Other files

Finally, we will have the rest of the classes of the program, as well as the application or main class. If you are designing an application with a graphical environment, there would be data representation classes or views. Similarly, in case of a web application, controllers and services would be missing.

5. Project Configuration

Let's take a closer look at the Hibernate configuration file. In the Hibernate configuration file we can set the options in a disorderly way, but it is recommended to group the option blocks for clarity and maintenance, as well as to indicate through comments what we are doing at that moment. We will see it with a complete example, which we will detail little by little in the following sections.

5.1. Hibernate.cfg.xml

XML
<?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE hibernate-configuration PUBLIC 
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

 <hibernate-configuration>
    <session-factory>
      <!-- Connection properties -->
      <!-- Driver JDBC -->
        <property name="connection.driver_class">
          com.mysql.cj.jdbc.Driver
        </property>

      <!-- Add ?createDatabaseIfNotExist=true to create database  -->
      <property name="connection.url">
        jdbc:mysql://localhost:3308/DBName
      </property>

      <!--user and pass -->
      <property name="connection.username">root</property>
      <property name="connection.password">root</property>

      <!-- extra conf -->

      <!-- JDBC connection pool for concurrent connections -->
      <property name="connection.pool_size">5</property>

      <!--  dialect connector. Useful for Foreing Keys-->
      <property name="dialect">
        org.hibernate.dialect.MySQL5InnoDBDialect
      </property>

      <!-- one thread one session -->
      <property name="current_session_context_class">thread</property>

      <!-- show "reals" SQL ops. only for development-->
      <property name="show_sql">true</property>

      <!-- DB maintenance -->
      <property name="hbm2ddl.auto">update</property>

      <!-- options hbm2dll:
        create : 
          create always DB when session factory is loaded. Data will be lost.
        update : 
          Data will be safe, but database structure will be update. 
          Useful in production.
        create-drop : 
          like create and dropping the database.
        validate:   
          check the mapping between database and beans.
      -->

      <!-- Mapping files. Can be combined-->

      <!-- mapping classes -->
      <mapping class="package.class1" />
      <mapping class="package.class2" />

      <!-- Maping files-->
      <mapping resource="class3.hbm.xml" />
      <mapping resource="class4.hbm.xml" />
    </session-factory>
</hibernate-configuration>

Notice than:

  • Show SQL queries option is high recommended to have it set to true, at least in first projects, to see how the mapping of objects to SQL queries actually occurs.
  • The hbm2ddl option is very powerful, since if we only start from the object-oriented model, Hibernate will create the database for us (obviously empty of data). We will see in a later practice another very interesting hbm2java will appear, which through reverse engineering will allow us to create our Beans from the relational design.
  • XML mapping files () must be together with the java classes, in the same package.
  • Mappings within the classes () refer to the Beans themselves, as we will see in next section.

5.2. Loading scripts

If you want to insert some data in your database test applications, it is a good idea to have a SQL script and load it automatically when hibernate configuration is loaded. You can add a file under src/main/resources called import.sql, and, after table creation, if exists, this script will be executed. This is the way to start a project with existing test data in our databases.

Moreover, if you want to execute more scripts, you can add specific files in hibernate.cfg.xml, as follows:

XML
1
2
3
<property name="hibernate.hbm2ddl.import_files">
  /import1.sql, /import2.sql
</property>

6. Loading configuration and Sessions

In order to load the previous configuration file, we must create a SessionFactory object throw we can create Session instances to connect to our database. The structure of this class will be always the same: load the configuration xml file, and then create the SessionFactory.

Java
public class HibernateUtil {

    private static final SessionFactory sessionFactory;

    // Código estático. Sólo se ejecuta una vez, como un Singleton
    static {
        try {
            // Creamos es SessionFactory desde el fichero hibernate.cfg.xml 
            sessionFactory = new Configuration()
                .configure(new File("hibernate.cfg.xml")).buildSessionFactory();    
        } catch (Throwable ex) {
            System.err.println("Error en la inicialización.  " + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

Attention

This implementation has been done with Singleton design pattern, in order to have a unique instance of SessionFactory