Improve Hibernate Caching Performance

In a Hibernate application, a common problem that people have is performance bottleneck. Principally in web applications, where is difficult to predict the number of users that will access the application, when the system faces an increase of simultaneous accesses, the response time decreases abruptly.

The common solution usually is the following:

  • Use a connection polling framework to hold some open connections ready to use (e.g. c3p0, Commons DBCP)
  • Enable second level cache using a well known cache provider (e.g. EhCache, OSCache, SwarmCache)
  • Use query cache to the most used queries

However, regardless the fact that the connection polling saves the time to open a new ready to use connection, fetching the connection from the pool is very expensive too. Principally in the case of using pooling frameworks that not handle concurrence and blocking very well (particularly I never made benchmarks comparing connection pooling frameworks, however some people in the web says that Commons DBCP have more locks in a concurrence scenario than c3p0, that handles betters multithreading accesses).

Few people know (or even care) that the Hibernate framework by default gets a connection from the pool every time that a session is created, regardless of hitting the cache or not. In other words, if your query spends 1ms to get the connection for the pool and 2ms to execute the statement, the caching will gain only the last 2ms because Hibernate always gets a connection, and adding the fact of the bad concurrence handling of the pooling framework, it can be a very bad bottleneck.

LazyConnectionDataSourceProxy

To solve this problem, the Spring framework provides a class named org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy (http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/jdbc/datasource/LazyConnectionDataSourceProxy.html). This class acts like a proxy to the real pooled data source fetching the connections lazily. This proxy will fetch the connection only when the first statement is created. In other words, if your hibernate query hits the cache, no connection is fetched from the data source at all.

To use this class is very easy and declarative through the Spring context file and no code changes are required, thanks to dependency injection:


<!-- The real DataSource, e.g. a pooled datasource registered at server JNDI -->
<bean id="dataSource">
<property name="jndiName" value="jdbc/MYDATABASE"/>
</bean>

<!-- Wrapping the real datasource into the Spring lazy datasource feature -->
<bean name="lazyConnectionDataSourceProxy">
<property name="targetDataSource" ref="dataSource" />
</bean>

<!-- Refer to the lazy datasource bean when injecting data sources (e.g. session factory, transaction manager) -->
<bean id="hibernateSessionFactory">
<property name="dataSource" ref="lazyConnectionDataSourceProxy" />
<!-- other configuration data … -->
</bean>