Getting Started with Hibernate 3 and NetBeans 6.5 Beta Part 2

Welcome back to the next part in this series, we’re going to take a closer look at using Hibernate. We’ll be revisiting the same SimpleHibernate project in the last article, so you’ll need to do that first before you continue. In this article, we’ll first go through the basics of using Hibernate and develop a more robust solution that we can use for a larger project.

Jump right in to the code

In the SimpleHibernate project, the only real code we had to write was in our simple test case, reproduced here for your reference:

  
User user = new User("Jaryl", "123");

SessionFactory factory = HibernateUtil.getSessionFactory();
Session session = factory.getCurrentSession();

try {
  session.beginTransaction();
  session.save(user);
  session.getTransaction().commit();

} catch (Throwable e) {
  if (session.getTransaction().isActive()) {
    session.getTransaction().rollback();
  }

  System.out.println(e.getMessage());
}
  

As you can see, we actually interact with our entity classes much like how we are used to. They are simply plain old Java objects, hence their names as POJOs.

Any Hibernate setup code is placed in HibernateUtil, which we generated easily enough. Using it is as simple as called a static method and getting the current session. Hibernate manages our connection to databases in sessions, not to be confused with HTTPSession in J2EE projects.

Within the try block, we see that we’re essentially trying to save the User object to database and that it is encapsulated within a transaction. If an exception is thrown, we rollback whatever we’ve done. This isn’t exactly useful in our simple example, but is good practice.

Handling Auto-incremented IDs

As a general rule of thumb, do not use database fields that hold business value as primary keys. Sure, they may be unique and never change, but as business rules change, you’re going find it difficult to change an existing solution.

Enter the surrogate key and auto-incremented IDs. In my project, I’ve used id as the primary key for every table. No exceptions. Later in the article, I’ll show you how this makes for an excellent shortcut. For now, we’ll explore how things work.

Let’s take a look at the mapping file generated by NetBeans, and you’ll see how your id field in your database is mapped.

  
    <id name="id" type="java.lang.Integer">
      <column name="id"/>
      <generator class="identity"/>
    </id>
  

So instead of treating the id attribute as a normal integer, Hibernate will understand how to use the auto-incremented value from the database. We should test it out though; let’s try to get the id in our test case. Just add this line before the end of the main method:

  
System.out.println(“Id of new user is: “ + user.getId());
  

If things work as expected (it should), you’ll see the id that was generated by MySQL. The point here is that not only does Hibernate transfer your data from object to the database, it actually keeps them in sync and that is the reason why you want a persistence framework in the first place.

Retrieving objects from the database

Now that we’re pretty familiar with how we can insert to the database, we can go on to retrieving information from it. Hibernate allows us to retrieve one object through the get method or using a query to retrieve a collection of objects.

  
SessionFactory factory = HibernateUtil.getSessionFactory();
Session session = factory.getCurrentSession();

try {
    session.beginTransaction();
    User user = (User) session.get(User.class, 1);
    session.getTransaction().commit();

} catch (Throwable e) {
    if (session.getTransaction().isActive()) {
    session.getTransaction().rollback();
  }

  System.out.println(e.getMessage());
}
  

As you can see, the codes are pretty much the same except that you’re using the get method and storing the results in a User object. Too simple (it could be simpler, like if you used Rails), so we’ll move on. Retrieving a list of records, however, is not so simple; Hibernate has a DSL called HQL, which is a pseudo database query language. It’s similar to SQL but works with any type of database provider as long as it is supported by Hibernate.

While covering HQL is beyond the scope of this tutorial, we’ll see a few simple but useful examples. The most basic thing you can do is to get all the rows in a table; Hibernate of course will return a collection of mapped POJOs. From here onwards, I’ll skip the boilerplate code that is required to get the Hibernate session and start a transaction.

  
Query query = session.createQuery("from User");
ArrayList<User> users = (ArrayList<User>) query.list();

for(User user : users) {
  System.out.println("User id: " + user.getId() + " Username: " + user.getUsername());
}
  

As you can see here, Hibernate gives us back an ArrayList which we can interact with like how we usually do. Next, we’ll do some authentication using Hibernate and HQL.

  
Query query = session.createQuery("from User where username = ? and password = ?");

query.setString(0, username);
query.setString(1, password);

return (User) query.uniqueResult();
  

Here, the logic is that we check if the username and password matches what the user is giving us. If both match, we’ll return the User object. If it doesn’t, we’ll return null which means the username/password pair failed authentication.

Data Access Objects

Using what you’ve learnt, you can pretty much replace your database code with Hibernate’s and cut down on your code length by a large margin. We can still improve on that situation though; following the MVC pattern that we discussed in the last article, we know that how we interact with Hibernate belongs in the Data layer.

You can imagine designing manager classes that do the grunt work in this case so that the controller and view doesn’t have to deal with Hibernate code. This is exactly what Data Access Objects are for. Business logic and rules should be kept within the Model layer, and spread in between the DAO and the entity classes.

Some of the responsibilities the DAO should have include CRUD operations so let’s do that. To keep things brief, I’ll only be demonstrating the create operation.

  
package data;

import org.hibernate.SessionFactory;
import org.hibernate.Session;
import data.entities.User;

public class UserDao {
    protected Session session;

    public UserDao() {
        SessionFactory factory = HibernateUtil.getSessionFactory();
        this.session = factory.getCurrentSession();
    }

    public void save(User user) {
        try {
            session.beginTransaction();
            session.save(user);
            session.getTransaction().commit();

        } catch (Throwable e) {
            if (session.getTransaction().isActive()) {
                session.getTransaction().rollback();
            }

            System.out.println(e.getMessage());
        }
    }
}
  

So now, how may we use the DAO? Very simply, like this:

  
UserDao dao = new UserDao();
User user = new User("jaryl", "123");
dao.save(user);
  

That’s much better. No Hibernate codes, everything is hidden behind your DAO and POJO. This is all fine and dandy, sure, but it could still be better. Imagine if you’re working on a sufficiently complex system and you have 12 entities to deal with, like say your IS203 group project. Most probably, you’ll want to have a DAO for each of them, and you’ll be writing that same save method every time. Not so good anymore huh?

Well you could copy and paste the codes, but that’s one really bad approach to code reuse. However, this is a good candidate for inheritance. We could create a generic DAO that takes care of these boilerplate responsibilities and individual DAOs can focus on its domain specific responsibilities. Again, I’ll only show you the create operation in the interest of brevity. Here, we’ll be doing some refactoring:

  
package data;

import org.hibernate.SessionFactory;
import org.hibernate.Session;

public abstract class GenericDao {
  protected Class persistedClass;
  protected Session session;

  public GenericDao(Class persistedClass) {
    SessionFactory factory = HibernateUtil.getSessionFactory();
    this.session = factory.getCurrentSession();
    this.persistedClass = persistedClass;
  }

  public void save(Object object) {
    try {
      session.beginTransaction();
      session.save(object);
      session.getTransaction().commit();

    } catch (Throwable e) {
      if (session.getTransaction().isActive()) {
        session.getTransaction().rollback();
      }

      System.out.println(e.getMessage());
    }
  }
}
  

The only difference is that we’re handling Object type objects, instead of User. This allows more than one type of DAO to reuse this method. Secondly, we’re storing a Class as an attribute. This isn’t actually needed for now, but you will need to have access to what kind of object we’re dealing with find operations.

So what’s the User DAO going to look like now? Here it is:

  
package data;

import data.entities.User;

public class UserDao extends GenericDao {
    public UserDao() {
        super(User.class);
    }
}
  

You might be wondering then, why don’t we just create a generic DAO and use it for everything? I might have to specify the class type when doing find operations, but it’s not really too much work. Well, don’t forget that you will need to include some methods specific to users, remember the authenticate method? Just add this method to your User DAO:

  
public User authenticate(String username, String password) {
  Query query = session.createQuery("from User where username = ? and password = ?");

  query.setString(0, username);
  query.setString(1, password);

  return (User) query.uniqueResult();
}
  

So now, every DAO that you create performs the create operation and in addition to that, your User DAO takes care of authentication as well. If we’re just going to put everything in the generic DAO, we end up with the big ball of mud anti-pattern.

Remember when I said that we could use a shortcut by using a surrogate key? Let’s work on it now. If all our tables used id as the unique identifier, we will be able to equip our generic DAO with a find method that can be shared across all entities. Consider the following:

  
public Object findById(int id) {
  Object object = (Object) session.get(persistedClass, id);
  return object;
}
  

This piece of code assumes that all your primary keys are integers. It uses the persisted class type that we stored as an attribute. It can be used by any table just like the save method that we created earlier. If you’ve got problems thus far, you can download the files here:

I’ll leave it as an exercise to you to come up with the rest of the CRUD operations for the generic DAO; you can start with retrieving an ArrayList of objects, since I’ve already provided sample code for you.

In the next article, I will cover how we can further improve on our generic DAO (yes that’s actually possible) and how we can use Hibernate’s relationship mapping mechanism between classes.