Hibernate – DAO – Java Tutorial

This tutorial will show how to use Database Access Objects using Hibernate in your java application.

To begin with we should create a table with a primary key. For this example we will create a table named Person with columns: ID, NAME, SURNAME, BIRTHDATE, SEX.We will use as PK the ID filed.

We will create a new java project named Persons in NetBeans and add in libraries the appropriate library according to the DB that we will use. In my case, that I use an oracle DB it is the ojdbc driver. Also change the main package to gr.persons

  • Hibernate Configuration

NetBeans is really helpful when it comes to generating the hibernate configuration file and also the entities from the DB. Select your project and go to New – Hibernate – Hibernate Configuration Wizard. After you select your select your DB connection yourhibernate.cfg.xml will be generated. Open the generated file and add this line under the last property:

[...]
    <!-- Enable Hibernate's automatic session context management -->
    <property name="current_session_context_class">thread</property>

Your hibernate.cfg.xml should now look like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
    <property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver</property>
    <property name="hibernate.connection.url">jdbc:oracle:thin:@171.0.0.0:1522:SID</property>
    <property name="hibernate.connection.username">YOUR_SCHEMA</property>
    <property name="hibernate.connection.password">YOUR_SCHEMA</property>
    <!-- Enable Hibernate's automatic session context management -->
    <property name="current_session_context_class">thread</property>
  </session-factory>
</hibernate-configuration>

* note here that YOUR_SCHEMA and the hibernate.connection.url will be according to your DB connection.

By the way, leave your hibernate.cfg.xml in the default package. It’s not the best practice, but for now leave it there.

Now in order to generate our POJO and map it with the DB we should first create a reveng.xml file. Again select your project and choose New – Hibernate – Hibernate Reverse Engineering Wizard. The wizard will connect to the DB based on the configurations in the hibernate.cfg.xml and it will prompt you to choose the wanted table(s). In our case we will choose the table Person.
*Note here, that if a table does not have a PK then we will not be able to generate the pojos and map it.

Now we are ready to generate our POJO and its mapping. Once again, select your project and go to New – Hibernate – Hibernate Mapping Files and POJOs from Database. Put them in a package gr.persons.entities.

Now in that package you will see a Person.java and also a Person.hbm.xml file. You have your object and it’s mapping accordingly. Moreover, if you go to hibernate.cfg.xml you will see that now it has also a mapping resource that points to the Person.hbm.xml file (line 12):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
    <property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver</property>
    <property name="hibernate.connection.url">jdbc:oracle:thin:@171.0.0.0:1522:SID</property>
    <property name="hibernate.connection.username">YOUR_SCHEMA</property>
    <property name="hibernate.connection.password">YOUR_SCHEMA</property>
    <!-- Enable Hibernate's automatic session context management -->
    <property name="current_session_context_class">thread</property>
    <mapping resource="gr/persons/entities/Person.hbm.xml"/>
  </session-factory>
</hibernate-configuration>

By the above steps we have configured Hibernate and we have finished with the configurations for our connection and mapping with the DB.

Hibernate is using SessionFactory to manage Sessions. These objects are quite heavy when it comes to resources and we have to be careful on how we use them in our application. That is why we will create a very common class, the HibernateUtil class that will manage our session. We can create a HibernateUtil class from NetBeans directly but we will create our own which will contain some more goodies.

HibernateUtil class

package gr.persons.utils;

import org.hibernate.Session;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.SessionFactory;

/**
*
* @author leonidas
*/
public class HibernateUtil {

private static final SessionFactory sessionFactory;

static {
try {
// Create the SessionFactory from standard (hibernate.cfg.xml)
// config file.
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Log the exception.
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}

public static SessionFactory getSessionFactory() {
return sessionFactory;
}

public static Session beginTransaction() {
Session hibernateSession = HibernateUtil.getSession();
hibernateSession.beginTransaction();
return hibernateSession;
}

public static void commitTransaction() {
HibernateUtil.getSession().getTransaction().commit();
}

public static void rollbackTransaction() {
HibernateUtil.getSession().getTransaction().rollback();
}

public static void closeSession() {
HibernateUtil.getSession().close();
}

public static Session getSession() {
Session hibernateSession = sessionFactory.getCurrentSession();
return hibernateSession;
}
}

As you can see from the HibernateUtil class, we have the Session, opening, committing and rolling back a transaction. We will use numerous times this methods in our application.

Now we are ready to use hibernate.

  • Database Access Objects (DAO)

It is not necessery to create DAO’s (Database Access Objects) in order to use hibernate from now on. However, it is better to seperate the implementation of the persisten framwork and the database layer from the rest of our application. It makes our application more flexible and better stuctured.

A good practice is to create a generic DAO that will be used from all of our specific DAO’s since some operations are common among all DAO’s. Our generic DAO will implement methods like save, merge, delete, findAll, findByID, findMany and findOne.

GenericDAO interface

package gr.persons.dao;

/**
 *
 * @author leonidas
 */
import java.io.*;
import java.math.BigDecimal;
import java.util.*;
import org.hibernate.Query;

public interface GenericDAO<T, ID extends Serializable> {

    public void save(T entity);

    public void merge(T entity);

    public void delete(T entity);

    public List<T> findMany(Query query);

    public T findOne(Query query);

    public List findAll(Class clazz);

    public T findByID(Class clazz, BigDecimal id);
}

GenericDAOImpl abstract class

package gr.persons.dao;

import gr.persons.utils.HibernateUtil;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;

/**
 *
 * @author leonidas
 */
public abstract class GenericDAOImpl<T, ID extends Serializable> implements GenericDAO<T, ID> {

    protected Session getSession() {
        return HibernateUtil.getSession();
    }

    public void save(T entity) {
        Session hibernateSession = this.getSession();
        hibernateSession.saveOrUpdate(entity);
    }

    public void merge(T entity) {
        Session hibernateSession = this.getSession();
        hibernateSession.merge(entity);
    }

    public void delete(T entity) {
        Session hibernateSession = this.getSession();
        hibernateSession.delete(entity);
    }

    public List<T> findMany(Query query) {
        List<T> t;
        t = (List<T>) query.list();
        return t;
    }

    public T findOne(Query query) {
        T t;
        t = (T) query.uniqueResult();
        return t;
    }

    public T findByID(Class clazz, BigDecimal id) {
        Session hibernateSession = this.getSession();
        T t = null;
        t = (T) hibernateSession.get(clazz, id);
        return t;
    }

    public List findAll(Class clazz) {
        Session hibernateSession = this.getSession();
        List T = null;
        Query query = hibernateSession.createQuery("from " + clazz.getName());
        T = query.list();
        return T;
    }
}

In our application we have only the Person class, so we will create the interface PersonDAO that will extend the GenericDAO and the class PersonDAOImpl that will extend the GenericDAOImpl and implement the PersonDAO. This is a common practice. For each and every DAO that we will create we will follow the same steps.

PersonDAO inteface

package gr.persons.dao;

import gr.persons.entities.Person;
import java.math.BigDecimal;

/**
 *
 * @author leonidas
 */
public interface PersonDAO extends GenericDAO<Person, BigDecimal> {
}

PersonDAOImpl class

package gr.persons.dao;

import gr.persons.entities.Person;
import gr.persons.utils.HibernateUtil;
import java.math.BigDecimal;
import org.hibernate.Query;

/**
 *
 * @author leonidas
 */
public class PersonDAOImpl extends GenericDAOImpl<Person, BigDecimal> implements PersonDAO {
}

In a way, someone could say that we are now ready. We can call the ProductDAO and start loading, saving objects e.t.c
For example:

PersonDAO personDAO = new PersonDAOImpl();
[...]
personDAO.findByID(null, BigDecimal.valueOf(1));
[...]
personDAO.save(person);
[...]
personDAO.findAll(Person.class);
[...]
personDAO.findOne(query);

Well… yes, this is functional of course but we are almost there!

First of all, we might want to find a person by its name and surname. This can be done by using the GenericDAO’s findOne(query) method. We could write in our program:

[...]
Person person = null;
String name = "John";
String surname = "Doe";
String sql = "SELECT p FROM Person p WHERE p.name = :name AND p.surname = :surname";
HibernateUtil.beginTransaction();
Query query = HibernateUtil.getSession().createQuery(sql).setParameter("name", name).setParameter("surname", surname);
person = findOne(query);
HibernateUtil.commitTransaction();
[...]

*Note that in the highlighted lines, we used the HibernateUtil to begin our transaction and also to commit our transaction.

This will do the job but it is better to create a segmentation in our code. Why not implement it inside our PersonDAO? This is what we will do, this is why we created the DAO’s at the fist place. We will change the PersonDAO and PersonDAOImpl like this:

PersonDAO

package gr.persons.dao;

import gr.persons.entities.Person;
import java.math.BigDecimal;

/**
 *
 * @author leonidas
 */
public interface PersonDAO extends GenericDAO<Person, BigDecimal> {

    public Person findByName(String name, String surname);
}

PersonDAOImpl

package gr.persons.dao;

import gr.persons.entities.Person;
import gr.persons.utils.HibernateUtil;
import java.math.BigDecimal;
import org.hibernate.Query;

/**
 *
 * @author leonidas
 */
public class PersonDAOImpl extends GenericDAOImpl<Person, BigDecimal> implements PersonDAO {

    public Person findByName(String name, String surname) {
        Person person = null;
        String sql = "SELECT p FROM Person p WHERE p.name = :name AND p.surname = :surname";
        Query query = HibernateUtil.getSession().createQuery(sql).setParameter("name", name).setParameter("surname", surname);
        person = findOne(query);
        return person;
    }
}

Now PersonDAO except the methods that inherits from GenericDAO it is also providing the findByName method.

We are now one step before finishing with the DAO design. Actually, we finished with the DAO design, we will no just use them.

Now we will create the classes that will manage our programs business logic. As you have noticed, our DAO’s do not have any transactions inside. That is crucial. We should never add transactions to our DAO’s since we should leave that logic outside of them. Let’s say for example that we might want to deal as one transaction the deletion of one object the update of an other one and the query for a third one. If we had transactions inside the save, delete and find methods of our DAO’s then we could not accomplish that.

That is why we will create a class that will manage our business logic and will talk with our DAO’s when it needs to interact with the DB. We will call them managers, PersonManager.class. PersonManager will implement our business logic and when they need to interact with the persistence it will call the PersonDAO. In our case, the PersonManager will not implement elaborate business, just the basics.

PersonManager interface

package gr.persons.session;

import gr.persons.entities.Person;
import java.math.BigDecimal;
import java.util.List;

/**
 *
 * @author leonidas
 */
public interface PersonManager {

    public Person findByPersonName(String name, String surname);

    public List<Person> loadAllPersons();

    public void saveNewPerson(Person person);

    public Person findPersonById(BigDecimal id);

    public void deletePerson(Person person);
}

PersonManagerImpl class

package gr.persons.session;

import gr.persons.dao.PersonDAOImpl;
import gr.persons.entities.Person;
import gr.persons.utils.HibernateUtil;
import gr.persons.dao.PersonDAO;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.NonUniqueResultException;
import org.hibernate.HibernateException;

/**
 *
 * @author leonidas
 */
public class PersonManagerImpl implements PersonManager {

    private PersonDAO personDAO = new PersonDAOImpl();

    public Person findByPersonName(String name, String surname) {
        Person person = null;
        try {
            HibernateUtil.beginTransaction();
            person = personDAO.findByName(name, surname);
            HibernateUtil.commitTransaction();
        } catch (NonUniqueResultException ex) {
            System.out.println("Handle your error here");
            System.out.println("Query returned more than one results.");
        } catch (HibernateException ex) {
            System.out.println("Handle your error here");
        }
        return person;
    }

    public List<Person> loadAllPersons() {
        List<Person> allPersons = new ArrayList<Person>();
        try {
            HibernateUtil.beginTransaction();
            allPersons = personDAO.findAll(Person.class);
            HibernateUtil.commitTransaction();
        } catch (HibernateException ex) {
            System.out.println("Handle your error here");
        }
        return allPersons;
    }

    public void saveNewPerson(Person person) {
        try {
            HibernateUtil.beginTransaction();
            personDAO.save(person);
            HibernateUtil.commitTransaction();
        } catch (HibernateException ex) {
            System.out.println("Handle your error here");
            HibernateUtil.rollbackTransaction();
        }
    }

    public Person findPersonById(BigDecimal id) {
        Person person = null;
        try {
            HibernateUtil.beginTransaction();
            person = (Person) personDAO.findByID(Person.class, id);
            HibernateUtil.commitTransaction();
        } catch (HibernateException ex) {
            System.out.println("Handle your error here");
        }
        return person;
    }

    public void deletePerson(Person person) {
        try {
            HibernateUtil.beginTransaction();
            personDAO.delete(person);
            HibernateUtil.commitTransaction();
        } catch (HibernateException ex) {
            System.out.println("Handle your error here");
            HibernateUtil.rollbackTransaction();
        }
    }
}

This was it. We are now 100% ready to continue with the rest of our application.

To sum up, we have our generic DAO’s that implement methods that are common among all DAO’s. We have our specific DAO’s that are extending the generic DAO’s and also adding their own methods and finally we have the managers that enclose the business logic of our application.

Now, we can call from our main class the manager and execute whatever we want:

PersonManager personManager = new PersonManagerImpl();

Person wanted = personManager.findByPersonName("Steven", "Seagal");

Person chuck = new Person(BigDecimal.valueOf(5), "Chuck", "Norris",new Date(), "Male");

personManager.saveNewPerson(chuck);

List allPersons = personManager.loadAllPersons();

You can find the full NetBeans project here. Note that you will have to change the schema in the hibernate.reveng.xml (match-schema=”BSCS_TEST”), Person.hbm.xml (schema=”YOUR_SCHEMA”). Also, you should change the hibernate.cfg.xml according to your DB connection.

P.S The ID of the Person is type of BigDecimal. This is due to oracle’s Number variable. In your example it my be, int or long or whatever!

EDIT:
If you want to map your POJO with annotations and not the .hbm.xml file take a look at this post.