Saturday, November 3, 2007

Introduction to Hibernate World

Overview
This tutorial is an introduction to Hibernate World. It will show you how to configure Hibernate by the XML file, how to implement a persistent class in JavaBean and connect with the HSQL DB which is a 100% java based SQL DBMS.

Required Software and Dependencies
First of all, you need to set up the environment for this tutorial. Here’s a list of the software and dependencies that you need to download.


Although this tutorial is making for the new Users, we won’t cover how to install Java SE, and Eclipse IDE. If you have some problems about how to make them working together, please try to search for the solutions from the Internet. There are plenty of them.

Project Overview

Let’s take a look in the Class Diagram. It will make you understand more clearly about what we are going to do.

Well, simple enough for the beginning. We will implement the Billing System. There is a customer, who buys the items and then we will create the bill. But this time just concentrate on the Customer class only. We will cover the other classes in the next tutorial. The Customer should have customerId property, which is an identity to make each Customer to be unique. Normally the identity property is a surrogate key. It means nothing to the business, just for referencing to the Customer class in the application only. The other properties for the Customer are firstName and lastName which are straightforward.

Setting up the Project
  • Create Java Project from Eclipse’s Panel by click on File → New → Java Project. Then, name the project as BillingSystem.

  • In the Java Setting window, click on Libraries Tab. Then add the needed libraries by clicking on Add External JARs button. You can find these JARs from Hibernate Core and HSQL DB that we have downloaded before. This is a list of JARs that we need for our project

    • hibernate3.jar

    • antlr.jar

    • asm.jar

    • asm-attrs.jar

    • c3p0.jar

    • cglib.jar

    • dom4j.jar

    • jta.jar

    • hsqldb.jar

    • commons-collections.jar

    • commons-logging.jar

  • After adding External JARs, you need to add JRE System Library. In the Java Setting Window, click on Add Library Button then choose JRE System Library. You may use Workspace default JRE or specify Alternate JRE yourself. Next click on Finish button.

  • Click on OK button. BillingSystem project should be display in the Package Explorer on the Left Side of the screen.

  • Right Click on BillingSystem, go to New → Source Folder, name the Source Folder as src, then click on Finish button.

Finally, your Eclipse IDE should have the project looks like this,


The Persistent Class
The Persistent Class is just a simple JavaBean class with the properties that map to the Database Table. Let’s create the Cutomer class. Right click on the src folder, choose New → Class, put billing.persistence as a package and name the class as Customer.

package billing.persistence;

public class Customer
{
   private Long customerId;
   private String firstName;
   private String lastName;

   public Customer ()
   {
   }

   public Long getCustomerId()
   {
      return customerId;
   }

   public void setCustomerId(Long customerId)
   {
      this.customerId = customerId;
   }

   public String getFirstName()
   {
      return firstName;
   }

   public void setFirstName(String firstName)
   {
      this.firstName = firstName;
   }

   public String getLastName()
   {
      return lastName;
   }

   public void setLastName(String lastName)
   {
      this.lastName = lastName;
   }

   @Override
   public String toString()
   {
      return "[customerId:" + getCustomerId() + "], [firstName:" + getFirstName() + "], [lastName:" + getLastName() + "]";
   }
}

The Customer class is following the JavaBean naming convention. Notice that, we also override the toString() method so it will be easy to monitor what value inside our JavaBean when debugging by calling System.out.println method.

Mapping File
The mapping file is an XML file that tells Hibernate what database table maps to the JavaBean class and what columns map to the JavaBean’s properties. It’s a good practice to keep the mapping file in the same folder where its JavaBean class is. So you should create Customer.hbm.xml by right click on billing.persistence package, then choose New → File and name the file as Customer.hbm.xml. Here’s the detail of the Customer mapping file.

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
   <class name="billing.persistence.Customer" table="CUSTOMER">
   <id name="customerId" column="CUSTOMER_ID" type="long">
      <generator class="native"/>
   </id>
   <property name="firstName" column="FIRST_NAME" type="string" />
   <property name="lastName" column="LAST_NAME" type="string" />
   </class>
</hibernate-mapping>
The mapping file begins with hibernate-mapping tag. Next is the class tag, this tag tells that the instance of class billing.persistence.Customer represents one record of CUSTOMER table. The id tag represents the identity property. From Customer.hbm.xml, it means column CUSTOMER_ID is a Primary Key. And type attribute is telling about Java Type. Hibernate will use it to translate Java to SQL data types and vice versa. The generator tag specifies how identity be generated. We use native value, which pick the best strategy in this case Hibernate will use identity startegy. The property tag maps each database column with the JavaBean’s property. From the example, firstName property will map to FIRST_NAME column in the CUSTOMER table.

Hibernate Configuration
To make Hibernate knows how to connect database, the hibernate.cfg.xml file is needed. This file configures the Database Connection and so on. You need to create this file in the src folder by right click on the src folder, choose New → File and name it as hibernate.cfg.xml. Here’s the example of hibernate.cfg.xml

<?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="connection.driver_class">org.hsqldb.jdbcDriver</property>
      <property name="connection.url">jdbc:hsqldb:mem:localhost</property>
      <property name="connection.username">sa</property>
      <property name="connection.password"></property>
      <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
      <property name="show_sql">true</property>
      <property name="hbm2ddl.auto">create</property>
      <mapping resource="billing/persistence/Customer.hbm.xml" />
   </session-factory>
</hibernate-configuration>

We need to provide the value of the properties so Hibernate can use that value to connect Database and configuring it.
  • connection.driver_class is the property that tells Hibernate which the Database Driver Class it will use. Since we use HSQL DB, the value will be org.hsqldb.jdbcDriver.

  • connection.url is the property to define the connection URL string. We will use our machine as a HSQL DB Server and because of the data in this tutorial doesn’t mean anything to us, so we can use memory database which means all data won’t be persist by using jdbc:hsqldb:mem:localhost.

  • connection.username and connection.password are the properties that define username and password to connect to the database server. We will use the default value, sa for username and blank for password.

  • dialect is the property that tells Hibernate about the database type that we use. The value should be match with the database.

  • show_sql is the property that tells Hibernate to print SQL Command. So we can see what the SQL Command look likes in the console window.

  • hbm2ddl.auto is the property that tell Hibernate to automatically validate or export schema DDL to the database when the SessionFactory is created. The value is create, which means the database schema will be created for us so we won’t bother about creating the database tables for our application.

  • mapping tag tells Hibernate to load the Hibernate Mapping file. Since Customer.hbm.xml is store in billing/persistence directory (the same package as the Customer class) so resource attribute will be billing/persistence/Customer.hbm.xml

The HibernateUtil Class
HibernateUtil class is a helper class that creates SessionFactory object and keep it so SessionFactory will be accessed in the application code through this class. SessionFactory can open a new Session. A Session seems like a delegate class for the JDBC Connection. It represents a single thread unit of work. To create HibernateUtil class, right click on src folder, choose New → Class, name the class as HibernateUtil and keep it in the billing.util package.


package billing.util;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil
{
   private static final SessionFactory sessionFactory;

   static
   {
      try
      {
         sessionFactory = new Configuration().configure().buildSessionFactory();
      }
      catch (Throwable ex)
      {
         ex.printStackTrace();
         throw new ExceptionInInitializerError(ex);
      }
   }

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

Regarding to this line of code,

sessionFactory = new Configuration().configure().buildSessionFactory();
Hibernate will search for the file name hibernate.cfg.xml in the root of the classpath. If it isn’t found, the exception will be thrown. If everything was fine, the SessionFactory will be created. Then we can access it by the static method getSessionFactory().

Storing and Loading the objects
Finally, it’s time to see how Hibernate works. We will create the Java Application Main class, to monitor how Hibernate stores and loads the objects. Here’s the source code of the Main class.

package billing.demo;

import org.hibernate.Session;
import org.hibernate.Transaction;
import billing.persistence.Customer;
import billing.util.HibernateUtil;

public class Main
{

   @SuppressWarnings("unchecked")
   public static void main (String [] args)
   {
      try
      {
         System.out.println ("Insert data...");
         Session session = HibernateUtil.getSessionFactory().openSession();
         Transaction tx = session.beginTransaction();
         Customer customer = new Customer();
         customer.setFirstName("John");
         customer.setLastName("Doe");
         session.save(customer);
         tx.commit();
         session.close();

         System.out.println ("Query data...");
         Long customerId = customer.getCustomerId();
         session = HibernateUtil.getSessionFactory().openSession();
         customer = (Customer)session.get(Customer.class, customerId);

         System.out.println(customer);
         session.close();

         System.out.println ("Update data...");
         session = HibernateUtil.getSessionFactory().openSession();
         tx = session.beginTransaction();
         customer.setFirstName("Joe");
         customer.setLastName("Ray");
         session.update(customer);
         tx.commit();
         session.close();

         System.out.println ("Query data...");
         session = HibernateUtil.getSessionFactory().openSession();
         customer = (Customer)session.get(Customer.class, customerId);
         System.out.println(customer);
         session.close();
      }
      finally
      {
         HibernateUtil.getSessionFactory().close();
      }
   }
}


  • Session represents a unit of work. In this Main class we call to store and load the objects.

  • Transaction is the API to specify the Transaction Boundaries. The transaction will begin with beginTransaction() method and it will end by commit() or rollback() method. It’s optional.

  • Query is the database query that can be written in Hibernate Query Language (HQL).

Before running the Main class, please check that your project should contains all the files like this,


To run the Main class, right click on Main.java, choose Run As → Java Application. You will see the Console window at the bottom of the screen. If you can’t find the Console window, click on the Window drop down menu → Show View → Console.
After running the Main class, you should see some text like this,


Insert data...
Hibernate: insert into CUSTOMER (CUSTOMER_ID, FIRST_NAME, LAST_NAME) values (null, ?, ?)
Hibernate: call identity()
Query data...
Hibernate: select customer0_.CUSTOMER_ID as CUSTOMER1_0_0_, customer0_.FIRST_NAME as FIRST2_0_0_, customer0_.LAST_NAME as LAST3_0_0_ from CUSTOMER customer0_ where customer0_.CUSTOMER_ID=?
[customerId:1], [firstName:John], [lastName:Doe]
Update data...
Hibernate: update CUSTOMER set FIRST_NAME=?, LAST_NAME=? where CUSTOMER_ID=?
Query data...
Hibernate: select customer0_.CUSTOMER_ID as CUSTOMER1_0_0_, customer0_.FIRST_NAME as FIRST2_0_0_, customer0_.LAST_NAME as LAST3_0_0_ from CUSTOMER customer0_ where customer0_.CUSTOMER_ID=?
[customerId:1], [firstName:Joe], [lastName:Ray]

Now let’s investigate each unit of work, begin with,
Insert data...
Hibernate: insert into CUSTOMER (CUSTOMER_ID, FIRST_NAME,
LAST_NAME) values (null, ?, ?)
Hibernate: call identity()

First we create a customer, set firstName to John and set lastName to Doe. After calling session.save method, Hibernate generates SQL Insert statement and executes it. You can see that we didn’t set the value for customerId property, since we declare it as an identity property and choose native strategy for it. Hibernate will insert the customerId by calling database identity automatically.
Query data...
Hibernate: select customer0_.CUSTOMER_ID as CUSTOMER1_0_0_, customer0_.FIRST_NAME as FIRST2_0_0_, customer0_.LAST_NAME as LAST3_0_0_ from CUSTOMER customer0_ where customer0_.CUSTOMER_ID=?
[customerId:1], [firstName:John], [lastName:Doe]

After inserting John Doe customer, we try to query the data by using customerId. The method session.get, will get the record in CUSTOMER table which have identity value (primary key) as the parameter that we pass to it. You can see the SQL Select statement that Hibernate generates. The last line shows the detail about the Customer object that we just got it from session.get method.
Update data...
Hibernate: update CUSTOMER set FIRST_NAME=?, LAST_NAME=? where CUSTOMER_ID=?

Next we change the firstName to Joe and also change the lastName to Ray. Then we call session.update method. Hibernate generates SQL Update statement and execute it.
Hibernate: select customer0_.CUSTOMER_ID as CUSTOMER1_0_0_, customer0_.FIRST_NAME as FIRST2_0_0_, customer0_.LAST_NAME as LAST3_0_0_ from CUSTOMER customer0_ where customer0_.CUSTOMER_ID=?
[customerId:1], [firstName:Joe], [lastName:Ray]
The last unit of work, it shows that after changing the properties value and calling session.update method, the data in Customer table have been change. The last line shows firstName and lastName properties have been change to Joe Ray.

Summery
Now you see how Hibernate works, learn how to configure Hibernate, create the mapping file and implement a simple Java Application using Hibernate. Although we don’t use this style of code much in the real world, it is the easiest way to understand Hibernate anyway. If you interested in Hibernate Configuration in more detail, please check the document in Hibernate website. In the next tutorial, you will see a more complex of the Billing System application, how to create association between persistent classes and the mapping file in more detail.

No comments: