Showing posts with label hibernate. Show all posts
Showing posts with label hibernate. Show all posts

Wednesday, October 21, 2009

Hibernate + Spring in Standalone application

Just a quick reminder howto use Hibernate + Spring in standalone application.
First comes hibernate session factory. I prefer to use separate file for hibernate, Instead of configuring it Spring's applicationContext.xml:

<bean name="hibernateSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation" value="hibernate.cfg.xml"/>
<!-- Those package will be scanned for classes with persistence annotations -->
<property name="packagesToScan" value="net.test.domain"/>
<!-- Annotated package. Contains package-level configuration. -->
<property name="annotatedPackages" value="net.test.domain"/>
</bean>

Transaction manager:

<bean id="hibernateTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="hibernate.session.factory"/>
</bean>
<tx:annotation-driven transaction-manager="hibernateTransactionManager"/>

Next is hibernate session. Hibernate guys suggest to use HibernateDaoSupport class as base for your DAOs, but to be completely honest, I'm not really comfortable with it, because it adds really weird dependency on Spring in DAO classes. Instead, it looks more natural to use dependency injection, which is really Spring's approach. To archive that all you need to do is mark session definition as being scoped proxy, set scope to 'prototype' and define SessionFactoryUtils#getSession as factory method. In result, each call to "any_method" in hibernate session bean instance is converted to SessionFactoryUtils.getSession().any_method():

<bean name="hibernateSession" class="org.springframework.orm.hibernate3.SessionFactoryUtils" factory-method="getSession"
scope="prototype">
<constructor-arg index="0" ref="hibernateSessionFactory"/>
<constructor-arg index="1" value="false"/>
<aop:scoped-proxy/>
</bean>

And all together:

<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

<bean name="hibernateSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation" value="hibernate.cfg.xml"/>
<!-- Those package will be scanned for classes with persistence annotations ->
<property name="packagesToScan" value="net.test.domain"/>
<!-- Annotated package. Contains package-level configuration. -->
<property name="annotatedPackages" value="net.test.domain"/>
</bean>

<bean id="hibernateTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="hibernateSessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="hibernateTransactionManager"/>
<bean name="hibernateSession" class="org.springframework.orm.hibernate3.SessionFactoryUtils" factory-method="getSession"
scope="prototype">
<constructor-arg index="0" ref="hibernateSessionFactory"/>
<constructor-arg index="1" value="false"/>
<aop:scoped-proxy/>
</bean>

<bean name="someDao" scope="singleton" class="net.test.TestDAO">
<property name="session" ref="hibernateSession"/>
</bean>
</beans>

In DAO class there is no need to worry about session management, "tx:annotation-driven" will do all work for you. The only thing, which developer has to think about is appropriate usage of transaction annotations.

Friday, August 15, 2008

Hibernate read-only cache strategy bug?

Hibernate has several cache stratagies, and one of them is ReadOnly. It looks like ReadOnly should be one which provides the best performance, which is also mentioned in Hibernate Reference. But just have a quick look at code of get method of that strategy:


public synchronized Object get(Object key, long timestamp) throws CacheException {
Object result = cache.get(key);
if ( result!=null && log.isDebugEnabled() )
log.debug("Cache hit: " + key);
return result;
}


That method is syncronized, which doesn't looks like good performance sign. Basicaly it is bottleneck specially for systems which require high-performance cache reading operations. I suppose, cache implementation itself has to take care about syncronisation stuff and stratgy shouldn't apply such strict restrictions. So it looks like obviouse bug.
Also, it blocks you from using of such feature like non-blocking loading if expired cache entries, which allows to serve the old content to subsequent threads until the cache entry has been updated.
NHibernate developers were also suprized with that syncronization and finaly have decided to remove it. See details here.
Regading to Java developers, as workaround, they can use NonstrictReadWriteCache strategy, which doesn't have syncronization and looks like suitable alternative for ReadOnly for the most cases.