Wednesday, October 27, 2010

Hibernate for beginners

Contents
1. Introduction
2. Hibernate Architecture
3. Building a simple application using hibernate
4. Application Configuration – hibernate.cfg.xml
5. Creating the POJO(Plain Old Java Objects)
6. Creating the Dao(Data Access Objects)
7. Testing the Dao functionality using Junit Test
8. Conclusion
9. References
10. Glosssary

1. Introduction

Hibernate is an open source java based library used to work with relational databases. Hibernate is an Object/Relational Mapping (ORM) tool for Java environments. The term Object/Relational Mapping (ORM) refers to the technique of mapping a data representation from an object model to a relational data model with a SQL-based schema. It is a very powerful ORM solution built on top of JDBC (Java Database Connectivity) API.

Hibernate not only takes care of the mapping from Java classes to database tables (and from Java data types to SQL data types), but also provides data query and retrieval facilities. It can also significantly reduce development time otherwise spent with manual data handling in SQL and JDBC.

Hibernate makes uses of persistent object called as POJO (Plain Old Java Objects) having simple getter and setter methods along with XML mapping documents for persisting objects into database.


2. Hibernate Architecture

hibernate architecture
Here are some definitions of the objects depicted in the diagrams:

SessionFactory (org.hibernate.SessionFactory)
Session factory is a threadsafe, immutable cache of compiled mappings for a single database. A factory for Session and a client of ConnectionProvider, SessionFactory can hold an optional (second-level) cache of data that is reusable between transactions at a process, or cluster, level. Only single instance of session factory is required for an application, so it is based on a singleton pattern. SessionFactory object is loaded at the start of the application.


Session (org.hibernate.Session)
Session is a single-threaded, short-lived object representing a conversation between the application and the persistent store (database, xml). It wraps a JDBC connection and is a factory for Transaction. Session holds a mandatory first-level cache of persistent objects that are used when navigating the object graph or looking up objects by identifier.

Persistent objects and collections
Short-lived, single threaded objects containing persistent state and business function. These can be ordinary JavaBeans/POJOs. They are associated with exactly one Session. Once the Session is closed, they will be detached and free to use in any application layer (for example, directly as data transfer objects to and from presentation).

Transient and detached objects and collections
Instances of persistent classes that are not currently associated with a Session. They may have been instantiated by the application and not yet persisted, or they may have been instantiated by a closed Session.

Transaction (org.hibernate.Transaction)
(Optional) A single-threaded, short-lived object used by the application to specify atomic units of work. It abstracts the application from the underlying JDBC, JTA or CORBA transaction. A Session might span several Transactions in some cases. However, transaction demarcation, either using the underlying API or Transaction, is never optional.

ConnectionProvider (org.hibernate.connection.ConnectionProvider)
(Optional) A factory for, and a pool of, JDBC connections . It abstracts the application from underlying Datasource or DriverManager. It is not exposed to application, but it can be extended and/or implemented by the developer.

TransactionFactory (org.hibernate.TransactionFactory)
(Optional) A factory for Transaction instances . It is not exposed to the application, but it can be extended and/or implemented by the developer.
Extension Interfaces

Hibernate offers a range of optional extension interfaces you can implement to customize the behavior of your persistence layer. See the API documentation for details.
Given a "minimal" architecture, the application bypasses the Transaction/TransactionFactory and/or ConnectionProvider APIs to communicate with JTA or JDBC directly.

Instance States :

An instance of persistent class can be in three different states,
These states are defined in relation to a persistence context. The Hibernate Session object is the persistence context. The three different states are as follows:

Transient
The instance is not associated with any persistence context. It has no persistent identity or primary key value.

Persistent
The instance is currently associated with a persistence context. It has a persistent identity (primary key value) and can have a corresponding row in the database. For a particular persistence context, Hibernate guarantees that persistent identity is equivalent to Java identity in relation to the in-memory location of the object.

Detached
The instance was once associated with a persistence context, but that context was closed, or the instance was serialized to another process. It has a persistent identity and can have a corresponding row in the database. For detached instances, Hibernate does not guarantee the relationship between persistent identity and Java identity.

Transaction Management :

Transaction Management service provides the ability to the user to execute more than one database statement at a time. For starting a transaction a method of begin transaction should be invoked on a Session object.(session.beginTransaction()).

If transaction is successfully executed it should be commited to persist the data in database using commit method transaction.commit();

In case of any exception or failure the transaction must be rollback to synchronize the database state otherwise database will throw an exception as current transaction is aborted. transaction .rollback();

3. Building a simple application using hibernate
Now we need to add the Hibernate and below libraries into the project . You can download the latest version of hibernate if you haven't already got if from www.hibernate.org. The version used in this tutorial is 3.0. you may find it easier to download the package containing all the dependencies so that you know that all the necessary jar files are present.

hibernate libraries
In this tutorial we are using database as postgressql 8.3 so we have to add the database dialect as per the database.
Database: Postgresql8.3.1
Hibernate version: hibernate 3.0

User_Details.sql : The below Sql query will be used for creating the table in the database.
[sourcecode language="css"]
CREATE TABLE user_details (
user_id integer NOT NULL,
user_name character varying(20),
user_password character varying(20),
CONSTRAINT "USER_pkey" PRIMARY KEY (user_id)
)
[/sourcecode]
4. Application Configuration – hibernate.cfg.xml
The hibernate.cfg.xml is a configuration file that is used for defining the db parameters like db username, password, connection url, connection pool size etc . This also includes the definig hbm (xml based hibernate mapping) files that have mapping of database column to java attributes.
hibernate.cfg.xml
[sourcecode language="css"]
<?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.connection.url">jdbc:postgresql://127.0.0.1:5432/qc</property>
<property name="hibernate.connection.username">postgres</property>
<property name="hibernate.connection.password">postgres</property>
<property name="hibernate.connection.pool_size">10</property>
<property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
<property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
<property name="current_session_context_class">thread</property>
<property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
<property name="show_sql">true</property>
<mapping resource="com/hibernatetest/demo/User.hbm.xml" />
</session-factory>
</hibernate-configuration>
[/sourcecode]


User.hbm.xml
[sourcecode language="css"]
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.hibernatetest.demo.User" table="user_details" schema="public" optimistic-lock="version">
<id name="userId" type="java.lang.Integer">
<column name="user_id" />
<generator class="increment" />
</id>
<property name="userName" type="string">
<column name="user_name" length="20" />
</property>
<property name="userPassword" type="string">
<column name="user_password" length="20" />
</property>
</class>
</hibernate-mapping>
[/sourcecode]


HibernateUtil.java : It is a java class that returns a session factory object that is used for getting the session(connection) object.
[sourcecode language="css"]
package com.hibernatetest.demo;

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


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

private static SessionFactory sessionfactory = null;

public static SessionFactory getSessionFactory()
{
Configuration cfg = new Configuration();
sessionfactory = cfg.configure("com/hibernatetest/demo/hibernate.cfg.xml").buildSessionFactory();
return sessionfactory;
}

}
[/sourcecode]
5. Creating the POJO(Plain Old Java Objects)
Now for persisting data to the database, hibernate requires a Java bean (POJO) object to be passed. For this we are writing a User’s pojo object having all getter and setter methods of attributes. These attributes will be work as carrier of data that will be stored in database. As these POJO Objects will travel across the network, these objects should implement the Serializable interface.
package com.hibernatetest.demo;

[sourcecode language="css"]
import java.io.Serializable;


/**
* This class is a POJO that works as a carrier of the
* data and will be stored in database by hibernate.
* @author rjain6
*/
public class User implements Serializable
{

private int userId;
private String userName;
private String userPassword;

public int getUserId()
{
return userId;
}

public void setUserId(int userId)
{
this.userId = userId;
}

public String getUserName()
{
return userName;
}

public String getUserPassword()
{
return userPassword;
}

public void setUserName(String userName)
{
this.userName = userName;
}

public void setUserPassword(String userPassword)
{
this.userPassword = userPassword;
}
}
[/sourcecode]
6. Creating the Dao (Data Access Objects)
Since this is a very simple application, there are only 1 Dao(Data Access object). is involved. This Dao class have methods to perform all the basic CRUD (Create, Read , Update, Delete ) functionalities.
[sourcecode language="css"]
package com.hibernatetest.demo;


import java.io.Serializable;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;


/**
* This is DAO class for performing database related functionalities.
* @author rjain6
*/
public class UserDAO
{

/**
* Creating a user in the database
*/
public int createRecord(User user)
{
Transaction tx = null;
Session session = HibernateUtil.getSessionFactory().openSession();
tx = session.beginTransaction();
Serializable s = session.save(user);
tx.commit();
return ((Integer)s).intValue();
}

/**
* Updating a user’s details in the database
*/
public boolean updateRecord(User user)
{
boolean isSuccess = false;
Transaction tx = null;
Session session = HibernateUtil.getSessionFactory().openSession();
try
{
tx = session.beginTransaction();
session.update(user);
tx.commit();
isSuccess = true;
} catch (HibernateException e)
{
isSuccess = false;
}
return isSuccess;
}

/**
* Deleting the user from the database
*/
public boolean deleteRecord(User user)
{
boolean isSuccess = false;
Transaction tx = null;
Session session = HibernateUtil.getSessionFactory().openSession();
try
{
tx = session.beginTransaction();
session.delete(user);
tx.commit();
isSuccess = true;
} catch (HibernateException e)
{
isSuccess = false;
}
return isSuccess;
}

/**
* Retrieving All users’ details from the database
*/
public List retrieveAllRecord()
{
Transaction tx = null;
Session session = HibernateUtil.getSessionFactory().openSession();
List ls = null;
tx = session.beginTransaction();
Query q = session.createQuery("from User");
ls = q.list();
return ls;
}

/**
* Retrieving All users’ names from the database
*/
public List retrieveAllUserName()
{
Transaction tx = null;
Session session = HibernateUtil.getSessionFactory().openSession();
List ls = null;
tx = session.beginTransaction();
//Native Query
Query q = session.createSQLQuery("select user_name from User_Details");
ls = q.list();
return ls;
}

}
[/sourcecode]
7. Testing the Dao functionality using Junit Test
The final stage in this simple tutorial is to create Junit test class to check the Session factory object and functionality of the data layer.
The contents of the class are shown below.
HibernateUtilTest.java : It is Test class for testing the working of session factory object. If Session factory object is not null, that means hibernate is able to get the database connection from DB.
[sourcecode language="css"]
package com.hibernatetest.demo;

import org.junit.Test;


/**
* This is a test class for chcecking is sessionfactory(database connection) is loaded by hibernate properly.
* @author rjain6
*/
public class HibernateUtilTest
{

/**
* Test method for {@link com.hibernatetest.demo.HibernateUtil#getSessionFactory()}.
*/
@Test
public void testGetSessionFactory()
{
System.out.println("session factory:"
+ HibernateUtil.getSessionFactory());
}

}[/sourcecode]
UserDAOTest.java :
[sourcecode language="css"]
package com.hibernatetest.demo;


import java.util.Collection;
import java.util.List;

import org.junit.Test;


/**
* This is test class having test methods to check the functionality of UserDAO class .
* @author rjain6
*/
public class UserDAOTest
{

@Test
public void createRecordTest()
{
UserDAO userDAO = new UserDAO();
User user = new User();
user.setUserName("demo");
user.setUserPassword("demo");
int recordId = userDAO.createRecord(user);
System.out.println("recordId:" + recordId);
}

@Test
public void updateRecordTest()
{
UserDAO userDAO = new UserDAO();
User user = new User();
user.setUserId(2);
user.setUserName("demo123");
user.setUserPassword("demo123");
boolean status = userDAO.updateRecord(user);
System.out.println("status:" + status);
}

@Test
public void deleteRecordTest()
{
UserDAO userDAO = new UserDAO();
User user = new User();
user.setUserId(3);
boolean status = userDAO.deleteRecord(user);
System.out.println("status:" + status);
}

@Test
public void retrieveRecordTest()
{
UserDAO userDAO = new UserDAO();
List list = userDAO.retrieveAllRecord();
if (isNullSafe(list))
{
for (int i = 0;i < list.size();i++)
{
System.out.println("UserName:" + ((User)list.get(i)).getUserName());
System.out.println("UserPassord:" + ((User)list.get(i)).getUserPassword());
}
}
}

@Test
public void retrieveAllUserNameTest()
{
UserDAO userDAO = new UserDAO();
List ls = userDAO.retrieveAllUserName();
if (isNullSafe(ls))
{
for (int i = 0;i < ls.size();i++)
{
System.out.println("UserName:" + ls.get(i));
}
}
}

/**
* @param ls
* @return
*/
private boolean isNullSafe(Collection col)
{
if (col != null && col.size() > 0)
return true;
else
return false;
}
}
[/sourcecode]

8. Conclusion
Hibernate is an ORM tool that is used to map the database structures to java objects at run time. Using a persistence framework like Hibernate allows developers to focus on writing business logic code instead of writing an accurate and good persistence layer which include writing the SQL Queries, JDBC Code , connection management etc.
9. References
1. https://www.hibernate.org/
2. http://docs.jboss.org/hibernate/core/3.3/reference/en/html/architecture.html

10. Glosssary
• ORM : Obejct Relational Mapping
• SQL : Structural Query Language
• HQL : Hibernate Query Language
• POJO : Plain Old Java Objects
• JDBC : Java Database Connectivity API
• HBM : Hibernate Mapping