Archive

Posts Tagged ‘Spring’

Spring + JPA + Hibernate + Tomcat + EHCache

May 2nd, 2010 5 comments

Having @ManyToMany(fetch=FetchType.EAGER) attributes can slow down retrieval quite significantly (up to 40 times slower).

I recall reading somewhere that FetchType.EAGER is the default for @ManyToMany associations. Also, from experience I noticed that setting FetchType.LAZY caused a org.hibernate.LazyInitializationException thrown with exception message similar to, failed to lazily initialize a collection of role: com.xyz.domain.EntityOne.images, no session or session was closed.

So, it seemed that the only other way to quickly reduce the time it took (for the retrieval) was to look into the caching options such as query caching, second-level caching, both of which are supported by Hibernate (the webapp’s JPA provider). For more information on second-level caching, please refer to this article.

Integrating Spring + JPA + Hibernate + Tomcat + EHCache took me a few hours this afternoon, but the effort paid off. The retrieval is now 40 times faster!

This post is summarizing the setup involved in getting them all to work together.

Relevant Section Of persistence.xml:

<provider>org.hibernate.ejb.HibernatePersistence</provider>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<properties>
  <property name="hibernate.cache.provider_class" 
    value="org.hibernate.cache.SingletonEhCacheProvider" />
  <property name="hibernate.cache.provider_configuration" value="/ehcache.xml" />
  <property name="hibernate.cache.use_second_level_cache" value="true" />
  <property name="hibernate.cache.use_query_cache" value="true" />
</properties>

Notes:

  • The persistence.xml is located at {tomcat}/webapps/{your-webapp}/META-INF.
  • I used org.hibernate.cache.SingletonEhCacheProvider instead of org.hibernate.cache.EhCacheProvider. I was getting a WARN message if I used org.hibernate.cache.EhCacheProvider. I referred to this post for a fix.

Relevant Section Of ehcache.xml:

  <diskStore path="user.dir/mywebapp-special-cache-folder"/>
 
  <defaultCache eternal="false" overflowToDisk="false"
    maxElementsInMemory="1000" timeToIdleSeconds="30" timeToLiveSeconds="60"/>
 
  <cache name="com.xyz.domain.EntityTwo" eternal="false" overflowToDisk="true" 
    maxElementsInMemory="1000" timeToIdleSeconds="300" timeToLiveSeconds="600"
    diskPersistent="true" diskExpiryThreadIntervalSeconds="300"/>
 
  <cache name="com.xyz.domain.EntityOne" eternal="false" overflowToDisk="true" 
    maxElementsInMemory="1000" timeToIdleSeconds="300" timeToLiveSeconds="600" 
    diskPersistent="true" diskExpiryThreadIntervalSeconds="300"/>
 
  <cache name="com.xyz.domain.EntityOne.images" eternal="false" 
    overflowToDisk="true" 
    maxElementsInMemory="1000" timeToIdleSeconds="300" timeToLiveSeconds="600" 
    diskPersistent="true" diskExpiryThreadIntervalSeconds="300"/>

Notes:

  • The ehcache.xml is located at {tomcat}/webapps/{your-webapp}/WEB-INF/classes.
  • The diskStore element indicates where the files to be used for caching will be stored for the entities I wish to be made persistent to disk. In my web application, the files are stored under {tomcat}/bin/{mywebapp-special-cache-folder}
  • diskPersistent="true" indicates that the disk store (for the specific entity) is persistent between cache and VM restarts. Please refer to the EHCache documentation on disk storage for more information.

Relevant JARs: under {tomcat}/webapps/{your-webapp}/WEB-INF/lib

  • ehcache-core-2.0.1.jar
  • hibernate3.jar
  • hibernate-jpa-2.0-api-1.0.0.Final.jar
  • slf4j-api-1.5.8.jar
  • slf4j-log4j12-1.5.6.jar
  • Spring 3.0.2 JARs..

Relevant Section Of Spring Configuration:

<!-- there should be a way out of hardcoding the location of the properties file -->
<bean 
  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="location" value="/WEB-INF/spring-hes-db.properties" />
</bean>
 
<!-- ENTITY MANAGER FACTORY -->
<!-- LocalEntityManagerFactoryBean did not work for me -->
<bean id="emf-p" 
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="persistenceUnitManager" ref="pum"/>
  <property name="persistenceUnitName" value="pu1"/>
  <property name="dataSource" ref="dataSource-p" />
  <property name="jpaVendorAdapter">
    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
      <property name="database" value="MYSQL" />
      <property name="showSql" value="true" />
      <property name="generateDdl" value="true" />
      <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
    </bean>
  </property>
</bean>
 
<!-- TRANSACTION MANAGER -->
<bean id="transactionManager" 
  class="org.springframework.orm.jpa.JpaTransactionManager">
  <property name="entityManagerFactory" ref="emf-p"/>
  <property name="dataSource" ref="dataSource-p"/>
</bean>
 
<!-- DATA SOURCES -->
<bean id="dataSource-p" 
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  <property name="driverClassName" value="com.mysql.jdbc.Driver" />
  <property name="url" 
    value="jdbc:mysql://${db.host}:${db.port}/${db.name}"/>
  <property name="username" value="${db.username}" />
  <property name="password" value="${db.password}" />
</bean>
 
<!-- JPA TEMPLATE -->
<bean id="jpaTemplate" class="org.springframework.orm.jpa.JpaTemplate">
 <property name="entityManagerFactory" ref="emf-p" />
</bean>
 
<!-- DAOs -->
<bean id="entityOneDao" class="hes.db.impl.EntityOneDAOImpl">
  <property name="jpaTemplate" ref="jpaTemplate"/>
</bean>
 
<!-- PERSISTENCE UNIT -->
<bean id="pum" 
  class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
  <property name="persistenceXmlLocations">
    <list>
      <value>META-INF/persistence.xml</value>
    </list>
  </property>
  <property name="dataSources">
    <map>
      <entry key="remoteDataSource" value-ref="dataSource-p" />
    </map>
  </property>
  <property name="defaultDataSource" ref="dataSource-p"/>
</bean>

Some of this may be redundant and will be cleaned up later.

If you have some better ideas, please do share. Thanks.

Categories: Java Tags: , , ,

Searching Using Fragment Of A String Using Spring

July 23rd, 2009 No comments

I encountered something rather annoying using Spring. I was query something similar to

SELECT last_name FROM users WHERE email_address LIKE ?

Spring execute the query but returned 0 results when I expected at least 1 (depending on how many characters of the last_name I had passed as a parameter to this query.

Only when I changed the relevant part of the code from

Object[] parameters = new Object[1];
parameters[0] = searchStr;

to

Object[] parameters = new Object[1];
parameters[0] = searchStr + "%";

did I get the correct number of records.

Here’s the complete code (parts modified for this post)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public List<String> retrieveLastNamesBasedOnEmailAddress(String searchStr)
{ // Constructing the query
  String sqlStr = "SELECT last_name FROM users WHERE email_address LIKE ?";
  // Constructing the parameter array
  Object[] parameters = new Object[1];
  parameters[0] = searchStr + "%";
  // Executing the query
  if(this.jdbcTemplate == null) 
    this.jdbcTemplate = new JdbcTemplate(getDataSource());
  List<String> list = this.jdbcTemplate.query(
      sqlStr, 
      parameters, 
      new SingleColumnRowMapper(String.class)
      );
  return list;
}

Depending on the permissible fragment of the the search parameter, perhaps adding in the % in front and back of the search parameter might be a better idea.

6
  parameters[0] = "%" + searchStr + "%";
Categories: Java Tags:

Getting The Next Auto-Increment Value Using A Spring DAO

January 31st, 2009 Comments off

The code below helps extract out the next value of the Auto-Increment column for a table. It has been tested using a MySQL database. You can try out the query first, SHOW TABLE STATUS LIKE ‘your_table_name;

This query returns the following fields: Name, Engine, Version, .. , Auto_increment, .. , Comment. The value stored under the Auto_increment column is the value that will be assigned to the next record when inserted into that table.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@SuppressWarnings("unchecked")
protected String retrieveNextAutoIncrementValue(String tableName)
{ String nextAutoIncrementValue = null;
  String sqlStr = "SHOW TABLE STATUS LIKE '" + tableName + "'";
  try
  {
    List<String> results = jdbcTemplate.query(sqlStr, new RowMapper() {
      public String mapRow(ResultSet rs, int i) throws SQLException
        { return rs.getString("Auto_increment"); }
      });
    if(results != null) nextAutoIncrementValue = results.get(0);
  }
  catch(Exception e)
  {
    System.out.println("Exception caught when executing : " + sqlStr + 
       ". Exception message : " + e.getMessage());
  }
  return nextAutoIncrementValue;
}

More information about SHOW TABLE STATUS can be found here.

Spring DAO Vs JDBC DAO

January 18th, 2009 No comments

Writing DAO code using Spring is so much better than the dark old days of writing it using plain JDBC. Its a lot less code to be written.

Take for example, a scenario where we want to write code to retrieve the value of a single column. In the past here’s what the code would look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int returnValue = 0;
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(sqlStr);
if(rs != null)
{ while (rs.next())
  { returnValue = rs.getInt(1);
    break;// since we want only a single record
  }
  rs.close();
}
rs = null;
stmt.close();
stmt = null;
return returnValue;

Using Spring DAO (actually implementing a sub class of org.springframework.jdbc.core.support.JdbcDaoSupport, here’s what the code looks like:

1
2
3
4
5
int returnValue = 0;
JdbcTemplate select = new JdbcTemplate(getDataSource());
List<Integer> list = select.query(sqlStr, new SingleColumnRowMapper(Integer.class));
if(list != null) returnValue = list.get(0).intValue();
return returnValue;

The main job of retrieval is done by the SingleColumnRowMapper.

Categories: Java Tags: