Including Hibernate with Spring

As mentioned in the article series of the Variations project I’ll use Spring as the core business logic framework. For the persistence Layer I’ll introduce now Hibernate.

Hibernate provides a mapping between Java objects and relational database tables and vice versa. Let’s look how to do it.

adding hibernate to the project

Since Spring comes with a module for Hibernate binding (spring-orm) it is easy to add Hibernate to the project. And because the little problem mentioned in a previous article is fixed in the Hibernate version 4.3.5 I switched back from c3p0 pooling to Spring.

And because of that switch, the datasource configuration changes a bit to the following:

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.h2.Driver" />
    <property name="url" value="jdbc:h2:file:../db/testdb" />
    <property name="username" value="sa" />
    <property name="password" value="" />
</bean>

The versions of the libraries used as I’m writing this article are:

  • Spring (core, orm, context): 4.0.5.RELEASE
  • Hibernate (core): 4.3.5.Final
  • H2: 1.4.178

To get Hibernate with Spring running you need a class which extends Spring’s “HibernateDaoSupport” class. This is a convenient way to access data with Hibernate.

One thing to be aware of: the HibernateDaoSupport does not enforce a required parameter, the sessionFactory, with constructor injection. You have to set this property manually when you configure your implementing class. Before we do that, I’ll show the sessionFactory configuration:

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="annotatedClasses">
        <list>
            <value>biz.hahamo.dev.variations.model.Driver</value>
            <value>biz.hahamo.dev.variations.model.Vehicle</value>
            <value>biz.hahamo.dev.variations.model.Route</value>
            <value>biz.hahamo.dev.variations.model.User</value>
            <value>biz.hahamo.dev.variations.model.ShippingNote</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>
    </property>
</bean>

The dataSource is the same bean which is re-defined at the beginning of the article.

You can see the highlighted lines: those configure all the classes which are marked with the @Entity annotation and are entities of the project. If your project grows and you get more entities, you will change this list of classes to a list of packages eventually. This can be done too. In this case you only have to replace all the highlighted lines above with the following line:

<property name="packagesToScan" value="biz.hahamo.dev.variations.model" />

This property tells Spring to scan the given package for entities. You can convert this single line to a list of values if you have multiple packages with entities (as for a bigger enterprise project it can happen).

The dialect is crucial for Hibernate however showing the SQL statements is not. If you run a big application in production I would always turn off the SQL logging because it can blow up your logs and take over your filesystem.

To manage your CRUD transactions you should include a transaction manager too:

<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"
    p:sessionFactory-ref="sessionFactory" />

Generic repository

As you can see in the source codes I’ve added a GenericRepository interface with an implementation for Hibernate. This is because with coding to the interface you can simply switch your implementation of the database access — and do not have to interfere with your implementation of the whole application.

This repository is type-less in the meaning that you do not have to add a type when you request an instance of it. This repository can handle various types of entities (Vehicle, Driver, etc) and provides you the basic functionality of loading and persisting objects.

Because this repository should be generic it accepts only queries of a given marker interface: PersistenceQuery. The interface is implemented by an abstract class which provides the basic functionality and the required methods for the concrete implementations.

General a query should have a name and a map of key-value pairs. If you need some other functionality (for example type mapping between database and database access library) you can implement it in the implementations.

And because of all this you need query creators, query factories which generate the queries for you to be executed against the database at the end. I think the code talks for itself but if you need some advice just write me a letter with your question and I’ll provide you with my answer.

As I mentioned some lines above the HibernateDaoSupport requires a sessionFactory via setter injection. Now I’ll show you how to configure this along with the GenericHibernateRepository:

<bean id="biz.hahamo.dev.variations.controller.repository.GenericRepository"
    class="biz.hahamo.dev.variations.controller.repository.internal.hibernate.GenericHibernateRepository"
    depends-on="liquibase">
    <property name="sessionFactory" ref="sessionFactory" />
    <constructor-arg ref="biz.hahamo.dev.variations.controller.repository.internal.hibernate.HibernateQueryCreator" />
</bean>

The highlighted line shows the setter injection of the sessionFactory.

Line 5 gives a constructor argument to the GenericHibernateRepository to enable query creation.

Line 3 tells that the repository depends on the bean liquibase — so the change sets of Liquibase have to run and after that can you start working with your application.

transactions

Reading the database goes smoothly with the defined transaction manager. However if you want to write something to the database you get an exception:

Exception in thread "main" org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
    at org.springframework.orm.hibernate4.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1135)
    at org.springframework.orm.hibernate4.HibernateTemplate$16.doInHibernate(HibernateTemplate.java:684)
    at org.springframework.orm.hibernate4.HibernateTemplate.doExecute(HibernateTemplate.java:340)
    at org.springframework.orm.hibernate4.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:308)
    at org.springframework.orm.hibernate4.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:681)
    at biz.hahamo.dev.variations.controller.repository.internal.hibernate.GenericHibernateRepository.save(GenericHibernateRepository.java:42)
    at biz.hahamo.dev.variations.controller.ApplicationService.saveData(ApplicationService.java:31)
    at biz.hahamo.dev.variations.App.main(App.java:27)

This tells you that you should change the flush mode from manual to something other — or remove the read-only attribute. I’ve chosen the latter.

To enable transaction handling with Spring you have to add an annotation to the class which should initiate a commit if the invoked method ran successfully. In this case I placed the @Transactional annotation on the ApplicationService class.

This makes all methods of the class read-write. This could lead to bad behaviour of your application if you walk along multiple transactions which shouldn’t write the database however somewhere your data is changes.

For this I suggest to use the annotation with it’s readOnly property set to true. And to enable specific methods to write to the database annotate those methods again with the @Transactional attribute. Note, that the readOnly property defaults to false — so if you add this annotation you get a read-write transaction.

After adding the annotation the ApplicationService class looks as follows:

// ... code omitted

import org.springframework.transaction.annotation.Transactional;

// ... code omitted
@Transactional(readOnly=true)
public class ApplicationService {

    private final GenericRepository repository;
    private final PersistenceQueryFactory persistenceQueryFactory;

    public ApplicationService(GenericRepository genericRepository, PersistenceQueryFactory persistenceQueryFactory) {
        this.repository = genericRepository;
        this.persistenceQueryFactory = persistenceQueryFactory;
    }

    public void loadData() {
        Driver d = repository.find(Driver.class, 1L);
        System.out.println(d);
        repository.findListByQuery(persistenceQueryFactory.createJpqlQuery("all.drivers", "FROM Driver"));
    }

    @Transactional
    public void saveData(Object entity) {
        repository.save(entity);
    }
}

And you can save the new Driver provided to the saveData method.

example code

The code is as always available at GitHub. Now you can read and create entries. However the code currently provided reads always the Driver with ID=1 and after that all Drivers to show how it goes. After that it creates a Driver always with the same data. So it is not as dynamic as it could be but without some words of entities I do not want to go any further currently. But for the impatient: the article about the entities is coming out next week.

Besides this I’ve added an entry in the history folder for this Spring-Hibernate integration before I do some GUI management. You can find the code here.

Future plans

Yes, it is time to add some functionality to enable management of all the data inside the application. So I’ll implement a simple UI at first in the console than with JavaFX. Ot if JavaFX does not work it out I’ll convert the application to a web app and deploy it to a server.

For the server I’ll take a Jetty or Tomcat however another option is the GAE but for that I’ll have to convert the database connection a bit.

So stay tuned and in some weeks we will have a working and usable application.

If you have something you want to see in the development issue a ticket at GitHub — or send me an email and I’ll issue a ticket for you. Than I’ll implement the request and discuss it here.

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s