Home > basic, grails, hibernate, patterns > Getting the Persistence Context Picture (Part II)

Getting the Persistence Context Picture (Part II)


Flattr this
The first article of this series [0] took a look at the basic patterns found in todays persistence frameworks. In this article we will have a look at how Hibernate APIs relate to those patterns and how Hibernate is utilized in Grails.

A Closer Look at Hibernate’s Persistence Context APIs

All data creation, modification and altering has to be done in a persistence context. A persistence context is a concrete software element that maintains a list of all object modifications and, in a nutshell, at the end of the persistence context life-time or business transaction synchronizes them with the current database state.

When developing with a modern web framework – as Grails is – it is most likely you don’t even have to care about opening a persistence context or closing it, or even know about how this could be done.

But as application complexity raises, you have to know Hibernate’s persistence context APIs and understand how they are integrated within the web application framework of your choice. Let us take a look at the most import APIs and how they correspond to persistence patterns.

The Registry Pattern or org.hibernate.SessionFactory

The SessionFactory class implements the registry pattern. A registry is used by the infrastructure-layer to obtain a reference to the current persistence context, or to create a new one if not found in the current context.

Usually, as noted in SessionFactory’s Java documentation, a session-factory refers to a single persistence provider. Most of the time, application need just a single session-factory. Indeed, if an application wanted to work across multiple databases, it would have to maintain multiple SessionFactory instances, one for each database.

Imagine a session-factory to be a configuration hub – it is the place where all configuration settings are read and used for constructing persistence contexts.

In a Grails application, the application’s session-factory can be easily obtained by declaring a property of type org.hibernate.SessionFactory:


class SomeService {

    SessionFactory sessionFactory

    void myServiceMethod()  {
        def session = sessionFactory.getCurrentSession()
        // ...
    }
}

The Grails application’s session-factoy is than injected by dependency injection since every Grails service class is a Spring-managed component. Other components include controllers, domain-classes and custom beans (either in beans.groovy, beans.xml, other bean definition XMLs or annotated Groovy/Java classes).

A Grails application’s session-factory is set-up by the HibernatePluginSupport class, which is a utility class used by Grails hibernate plugin. When taking a look at the source code you’ll find out that the code uses Grails Spring builder DSL to declare a ConfigurableLocalSessionFactoryBean. This type of bean is usually used in Spring applications to create a Hibernate session-factory instance during application bootstrap and to keep track of it during the entire life-time of the application-context.

//...
sessionFactory(ConfigurableLocalSessionFactoryBean) {
    dataSource = dataSource
    // ...
    hibernateProperties = hibernateProperties
    lobHandler = lobHandlerDetector
}
//...

Btw, if we would have to create a session-factory within a plain Groovy application, it wouldn’t get much harder:


def configuration = new Configuration()
    .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect")
    .setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test")
    .setProperty("hibernate.order_updates", "true")
    // ...

def sessionFactory = configuration.buildSessionFactory()

The Configuration class can be used to configure a session-factory programatically, other options would be to use a properties-file or an XML file (named hibernate.properties or hibernate.cfg.xml). If using any of the file-based configurations, take care your configuration file can be loaded by the current class-loader, therefore put it in the class-path’s root directory.

Grails configuration of Hibernate’s session-factory is pretty much hided from application developers. In order to provide a custom hibernate.cfg.xml, just put it in the grails-app/conf/hibernate folder.

The Persistence-Context Pattern or org.hibernate.Session

The Session builds the heart of Hibernate: it resembles a persistence context. Thus, whenever the application needs to access object-mapping functionality in either form, it needs to work with an instance of type Session.

The Session interface provides a bunch of methods letting the application infrastructure interact with the persistence context:

        // ...
	public Query createQuery(String queryString) throws HibernateException;

	public SQLQuery createSQLQuery(String queryString) throws HibernateException;

	public Query createFilter(Object collection, String queryString) throws HibernateException;

	public Query getNamedQuery(String queryName) throws HibernateException;

	public void clear();

	public Object get(Class clazz, Serializable id) throws HibernateException;

	public void setReadOnly(Object entity, boolean readOnly);

	public void doWork(Work work) throws HibernateException;

	Connection disconnect() throws HibernateException;

	void reconnect() throws HibernateException;

	void reconnect(Connection connection) throws HibernateException;
        // ...

Whenever e.g. a query is created by one of the querying methods, all objects which are retrieved are automatically linked to the session. For each attached (Hibernate term for “linked”) object, the session holds a reference and meta-data about it. Whenever a transient Groovy object is saved, it gets automatically attached to the current session. Notice that this is a unidirectional relationship: the session knows everything whereas the attached object instances don’t know anything about being linked to a session.

Lazy and Eager Loading

In regard to attaching objects to the current session, you need to know the concepts of lazy and eager loading of object relationships.

Whenever a persistent class A references another persistent class B, A is said to have a relationship with B. Object relationships are mapped either with foreign keys or relationship tables in the underlying database schema. As default, Hibernate uses a lazy loading approach: whenever a root object with relations to other objects is loaded, the related objects are not loaded. The other approach would be eager loading, where the object relationship is loaded with the root object.

Lazy vs. Eager Loading

Lazy loading does not hurt as long as objects are attached to a persistence context. Although, if the persistence context is closed, there is no way to navigate over a lazy loaded relationship. Whenever application code needs to access lazy relationships this leads to a lazy loading exceptions.

Obtaining a Session

Per default, a session instance can be obtained using a session-factory instance:


def session = sessionFactory.openSession()
def tx = session.beginTransaction()

// ... work with the session

tx.commit()
session.close()

As it is the case with the code sample above, most of the time application code is working in a transactional context, that is, the current method is executed within a single transaction. Therefore, it is a common idiom to open a transaction with the beginning of a session, although this is not enforced by Hibernate’s API. If we would not use transaction boundaries, we could just omit the method call to beginTransaction:


def session = sessionFactory.openSession()

// ... work with the session

session.close()

You need to be careful in this scenario. If Hibernate obtains a JDBC connection, it automatically turns autocommit mode off by setting jdbcConnection.setAutoCommit(false). Indeed, this is the JDBC way to tell the database to start a new transaction. However, how the database driver reacts on pending transactions is not specified, an application runs into undefined behavior.

General Session-Handling in Grails

As manual session handling can get tricky, web frameworks like Grails hide most of these problems. The Grails’ Object Relational Mapping (GORM) layer is a thin layer above Hibernate 3. Grails uses this layer to enrich domain classes with a lot of DAO like functionality. E.g. to each domain class so-called dynamic finders are added, which most of the time completely replace the need for data access objects (DAOs). Handling of Hibernate sessions is mainly hidden by GORM which internally uses Spring’s Hibernate integration and Hibernate.

Whenever executing a GORM query Grails internally creates a HibernateTemplate. A HibernateTemplate is a neat way to get defined access to a Hibernate session. It completely hides getting the session-factory and retrieving a session. Clients only need to implement callback methods, which are than called on execution of that template. Let’s take a look how such templates are used when executing e.g. a dynamic finder method like findBy.


class SomeController {
  def myAction()  {
    def User user = User.findByLogin(params.id)
    // ...
  }
}

When invoking the static findBy dynamic finder method, the following code is executed:


// ...
return super.getHibernateTemplate().execute( new HibernateCallback() {
    public Object doInHibernate(Session session) throws HibernateException, SQLException {
        Criteria crit = getCriteria(session, additionalCriteria, clazz);
	// ... do some criteria building

        final List list = crit.list();
        if(!list.isEmpty()) {
            return GrailsHibernateUtil.unwrapIfProxy(list.get(0));
        }
        return null;
     }
});

As can be seen, Grails internally does nothing more than creating a Spring HibernateTemplate and in its doInHibernate callback, creates a plain Hibernate Criteria object which is used to specify object queries. Spring hides the code of finding the current session and setting properties according to the current program context, GORM adds this functionality and does all Groovy meta-programming stuff (adding static methods etc. to the domain’s meta class).

The same is true for saving domain objects using GORM’s save method:

protected Object performSave(final Object target, final boolean flush) {
        HibernateTemplate ht = getHibernateTemplate();
        return ht.execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                session.saveOrUpdate(target);
                if(flush) {
                    // ...
                    getHibernateTemplate().flush();
                    // ...
                }
                return target;
            }
        });
}

Session Flushing

Since a session spans a business transaction (remember, not the same as a technical transaction) it might be left open by the infrastructure-layer over several user interaction requests. The application needs to ensure that a session is closed and its state synchronized with the database at some time, which is called flushing a session.

As we have already seen in the Grails source code above, flushing is mainly handled by the web framework, but programmers should know the point-cuts where it actually happens:

  • whenever a Transaction gets committed
  • before a query is executed
  • if session.flush() is called explicitly

Be aware that flushing is a costly operation in a persistence context, as Hibernate needs to synchronize the current object model in memory with the database. Programmers could change the default behavior described above by setting an alternate flush mode on the current session:

def session = sessionFactory.openSession()
session.setFlushMode(FlushMode.NEVER)

FlushMode.NEVER in this case means that session flushing is deactivated, only explicit calls to session.flush() triggers it.

In Grails, session flushing is done after each controller call, due to Spring’s OpenSessionInView interception mechanism. In order to access lazy-loaded properties in GSP pages, the session is not closed completely after a controller’s method call but after response rendering is done. Therefore, it sets session flushing mode to FlushMode.NEVER after a controller method call to avoid DB modifications caused by GSP page code.

Another place where sessions get flushed, is at the end of each service method call (as long as the service is marked as being transactional or is annotated with @Transactional):

class SomeService {
    static transactional = true

    def someMethod()  {
       // ... transactional code
    }
}
class SomeService {

    @Transactional
    def someMethod()  {
       // ... transactional code
    }
}

When doing integration tests on Grails classes, you need to remind these point-cuts where sessions get flushed. To make things even more complicated, there is one additional thing that is different in integration tests: each integration test method runs in its own transaction, which at the end is rollbacked by Grails testing classes. E.g. if testing a controller’s save method, chances are you can’t find an SQL INSERT or UPDATE statement in database logs. This is the intended behavior, but it causes confusion if bugs dealing with persistence issues need to be reproduced by test-cases.

If it is about transactions in integration tests, there is a way to deactivate transaction boundaries there:

class SomeTest extends GrailsTestCase {
    static transactional = false

    @Test
    def testWithoutTransactionBoundary()  {
       // ... transactional code
    }
}

Summary

In this article we took a look at how Grails and GORM handles Hibernate’s basic APIs: the SessionFactory and the Session. The next article in this series will deal with more advanced features: GORM in batch-jobs and conversational state management.

[0] Getting the Persistence Context Picture (Part I)
[1] Hibernate Project
[2] Spring Hibernate Integration
[3] Grails GORM Documentation

Categories: basic, grails, hibernate, patterns
  1. April 9, 2010 at 12:29 am

    Great stuff! Looking forward to the next part.

  2. July 4, 2010 at 11:36 am

    Small point regarding the section on session flushing: FlushMode.NEVER has been deprecated in favour of FlushMode.MANUAL for a while now, although the semantics are the same.

  1. No trackbacks yet.

Leave a reply to Ewan Dawson Cancel reply