Pages

Saturday, 17 November 2012

Hibernate as Persistence Provider and ORM Solution – Part II


Continues from Part I

Configuring Hibernate Framework

The instance of org.hibernate.cfg.Configuration is used to manage Hibernate configuration that represents an entire set of mappings of an application’s Java types to an SQL database. These mappings are compiled from various XML mapping files or from Java 5 Annotations. The org.hibernate.cfg.Configuration is used to build an immutable org.hibernate.SessionFactory.
Hibernate provides following types of configurations
  1. hibernate.cfg.xml – A standard XML file which contains hibernate configuration and which resides in root of application’s CLASSPATH
  2. hibernate.properties – A Java compliant property file which holds key value pair for different hibernate configuration strings.
Programmatic configuration – This is the manual approach. The configuration can be defined in Java classes.

It is noticeable here that if both hibernate.cfg.xml and hibernate.properties files are provided simultaneously in an application then hibernate.cfg.xml gets precedence over hibernate.properties.


Pros and Cons of Hibernate Framework


Pros

  • Reduces development effort for persisting data from business tier.
  • With help of object relational mapping the database operations on tables can be performed in an object oriented style.
  • It allows caching of persistent objects that can be used for the performance improvement.
  • It is database vendor neutral.
  • Developer is not required to know SQL statements.

Cons

  • For highly data intensive applications, hibernate does not perform up to the mark due to memory issues.
  • Hibernate is suitable only if the database schema is well designed and not very complex.
  • Testing and debugging memory leaks might take a lot of time because the framework does not provide the control to write an optimized query.
  • Sometimes hibernate may generate a vendor specific query in the background that is performance wise very poor.
  • Needs high level of expertise for handling the performance tuning issues.


Using SessionFactory, Session and Transaction objects in an application


If there is single data source to which application needs to connect then only one SessionFactory object is enough for the entire application. However if an application is supposed to be connected to multiple data sources then in that case the number of SessionFactory objects in the application should be equal to the number of data sources. In most of the cases it is the best practice to use single hibernate session for a single request. If we tend to use same session for multiple requests then it means more number of persistent objects will reside in the first level cache which is a memory leak and thus not desired.

Whenever a Servlet receives any request a new thread is assigned to that request and if we follow the session-per-request approach then we will always have a unique session for each thread created against each request.

Now the question is how we can ensure that for each thread there is always a unique session? Simply use ThreadLocal variables to handle Hibernate sessions and that is it. It is noticeable that although a session can span over multiple transactions yet on a given point of time there can not be more than one active transactions as in Hibernate there is no concept of nested transactions. Therefore we can also use ThreadLocal variables to handle Hibernate transactions. Please take a look at the following utility class that does provide this functionality.
import java.sql.SQLException;
import java.util.logging.Logger;
import org.hibernate.Transaction;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
 
public final class HibernateUtil {

   private static final Logger logger  = Logger.getLogger(HibernateUtil.class.getSimpleName());
   private static final ThreadLocal<Session> threadSession =
      new ThreadLocal<Session>();
   private static final ThreadLocal<Transaction> threadTransaction =
      new ThreadLocal<Transaction>();
   private final static SessionFactory sessionFactory;

   static {
      sessionFactory = buildSessionFactory();
   }
    
 
   private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new AnnotationConfiguration()
              .configure()
                    .buildSessionFactory();
        } catch (Throwable ex) {
            logger.warning("Initial SessionFactory creation failed.");
            throw new ExceptionInInitializerError(ex);
        }
   }

   public static Session getCurrentSession() {
      Session s = threadSession.get();
      try {
         if (s == null || !s.isOpen()) {            
            logger.info("Opening new Session for this thread.");            
            s = sessionFactory.openSession();
            threadSession.set(s);
         }
         else {            
               logger.info("Using current session in this thread.");            
         }
      } catch (HibernateException ex) {
         throw new IllegalStateException("unable to open hibernate session",ex);
      }

      return s;
   }

   public static WrappedSession getWrappedSession() {
      return new WrappedSession(getCurrentSession());
      
   }

   public static void closeSession() {
      try {
         final Session s = threadSession.get();
         if (s != null && s.isOpen()) {
            logger.info("Closing Session of this thread.");
            s.close();
         }
      }
      catch (HibernateException ex) {
         logger.warning("Failed to close session of this thread.");
      }
      finally {
         threadSession.set(null);
      }
   }

   public static void beginTransaction() {
      Transaction tx = threadTransaction.get();
      try {
         if (tx != null && !tx.isActive()) {
            tx = null;
            threadTransaction.set(null);
         }
         if (tx == null) {
            
            logger.info("Starting new database transaction in this thread.");       
            tx = getCurrentSession().beginTransaction();
            threadTransaction.set(tx);
         }
         else {
            
            logger.info("Using current database transaction in this thread.");            
         }
      }
      catch (HibernateException ex) {
         throw new IllegalStateException("Failed to start new database transaction in this thread.");
      }
      finally {
         if (threadSession.get() == null || !threadSession.get().isOpen()) {
            getCurrentSession();
         }
      }
   }

   public static void commitTransaction() {
      final Transaction tx = threadTransaction.get();
      try {
         if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack())
         {                            
            logger.info("Flushing session and committing transaction of this thread.");
            Session s = getCurrentSession();
            s.flush();
            tx.commit();
         }
      }
      catch (HibernateException ex) {
         rollbackTransaction();
         logger.warning("Failed to flush session and commit transaction of this thread.");
      }
      finally {
         threadTransaction.set(null);
         closeSession();
      }
   }

   public static void rollbackTransaction() {
      final Transaction tx = threadTransaction.get();
      try {
         if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
            logger.info("Trying to rollback database transaction of this thread.");
            tx.rollback();
         }
      }
      catch (HibernateException ex) {
         logger.warning("Failed to rollback database transaction of this thread.");
      }
      finally {
         threadTransaction.set(null);
         closeSession();
      }
   }
}

Friday, 2 November 2012

Hibernate as Persistence Provider and ORM Solution - I

Introduction

Since the very beginning of Hibernate framework it has been continuously gaining support and popularity. I am therefore very much interested in covering important aspects of Hibernate framework in my current as well as upcoming posts on Java technologies.

Hibernate was started in 2001 by Gavin King as an alternative to using EJB2-style entity beans. It is important to know what persistence actually is before starting our discussion on Hibernate. Persistence is a process of storing the data to some permanent medium and retrieving it back at any point of time even after the application that had created the data ended. The purpose behind this framework was to offer better persistence capabilities by simplifying the complexities and allowing for missing features.

Hibernate is an object-relational mapping (ORM) framework where ORM can be defined as,


A programming method for mapping the objects to the relational model where entities/classes are mapped to tables, instances are mapped to rows and attributes of instances are mapped to columns of table”.

 

Basic Architecture of Hibernate 

 

It is important to note here that the persistent objects synchronize data between application and database layers.

 

Detailed Architecture of Hibernate

 


A Java class mapped to any database table is called an Entity. The instance of an entity becomes a persistent object with help of SessionFactoy which is a singleton instance that implements Factory design pattern. SessionFactory loads hibernate.cfg.xml file and with the help of TransactionFactory and ConnectionProvider implements all the configuration settings on a database.
The Session object is created out of a SessionFactory object and it simply represents a single connection with database. It is also noticeable that a Session can span through multiple transactions where each transaction represents a single atomic unit of work. Hibernate also provides built-in Transaction APIs which abstracts away the application from underlying JDBC or JTA transaction.

SessionFactory

  • A factory for org.hibernate.Session instances.
  • A thread-safe, immutable cache of compiled mappings for a single database.
  • A client of org.hibernate.connection.ConnectionProvider.
  • Optionally maintains a second level cache of data that is reusable between transactions at a process or cluster level.

Session

  • A single-threaded, short-lived object representing a conversation between the application and the persistent store.
  • Wraps a JDBC java.sql.Connection.
  • Factory for org.hibernate.Transaction.
  • Maintains a first level cache of the application’s persistent objects and collections; this cache is used when navigating the object graph or looking up objects by identifier.

Persistent/Attached objects

  • Short-lived, single threaded objects containing persistent state and 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.

Transient/Detached objects

  • Instances of entity classes that are not currently associated with an active Session.

Transaction (org.hibernate.Transaction)

  • An optional, single-threaded, short-lived object used by the application to specify atomic units of work.
  • Although the use of Transaction is optional yet the Transaction demarcation is never optional.
  • It abstracts the application from the underlying JDBC, JTA or CORBA transaction.
  • A Session might span through several transactions.

ConnectionProvider (org.hibernate.connection.ConnectionProvider)

  • It provides pool of JDBC connections.
  • It abstracts the application from underlying javax.sql.DataSource or java.sql.DriverManager.

TransactionFactory (org.hibernate.TransactionFactory)

  • A factory for org.hibernate.Transaction instances.