Tuesday, August 25, 2009

Adding a second In-Memory datasource to your Spring configuration

This was something I put together really quick but it is useful none the less. I had to add a second in-memory database to my spring configuration in order to store some data in memory, map Hibernate objects to it and have it cleaned up when the user's session dies and recreated when the server starts.

I really never have used memory databases. I have never had a requirement to use one and I always have Oracle, PostgreSQL, SQL Server or MySQL laying around to use. I looked around and took a poll from the user's group and it came down to Derby or HSQLDB. Derby is not officially supported by Hibernate and I had some issues getting it to work so I chose to go with HSQLDB.

Enough talk...now we look at the integration into Spring. Remember I already have one datasource, so I had to add a second one in the applicationContext.xml.

<bean id="inMemDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- <property name="driverClassName"><value>org.apache.derby.jdbc.EmbeddedDriver</value></property>
<property name="url"><value>jdbc:derby:InMemoryDatabase;create=true</value></property> -->

<property name="driverClassName"><value>org.hsqldb.jdbcDriver</value></property>
<property name="url"><value>jdbc:hsqldb:mem:SessionInfo</value></property>
<property name="username"><value>sa</value></property>
<property name="password"><value></value></property>


</bean>



<bean id="inMemorySessionFactory"
class="com.application.spring.AutomatedAnnotationSessionFactoryBean">
<property name="dataSource" ref="inMemDataSource" />

<property name="automaticAnnotatedPackages">
<list>
<value>com.application.domain.memory</value>
</list>
</property>
<property name="annotatedPackages">
<list>
<value>com.application.domain.memory</value>
</list>
</property>

<!-- annotated source files -->
<!-- <property name="annotatedClasses">
<list>
<value>example.Account</value>
<value>example.AccountDetail</value>
<value>example.Employee</value>
</list>
</property> -->

<property name="hibernateProperties">
<props>
<prop key="hibernate.generate_statistics">true</prop>
<!-- <prop key="hibernate.dialect">org.hibernate.dialect.DerbyDialect</prop> -->
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</prop>

<prop key="hibernate.show_sql">false</prop>

<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
<prop key="hibernate.validator.apply_to_ddl">true</prop>
<!-- <prop key="hibernate.validator.autoregister_listeners">true</prop>
<prop key="hibernate.validator.apply_to_ddl">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop> -->
<!-- <prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</prop> -->
</props>
</property>

<property name="entityInterceptor">
<ref bean="modificationInterceptor"/>
</property>

</bean>


<!-- Hibernate Template definition -->
<bean id="inMemoryHibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<constructor-arg ref="inMemorySessionFactory"/>
<constructor-arg type="boolean" value="false"/>
</bean>


Now I created a simple domain object to map.



@Entity
@Hibernate
@Table(name="SIMPLE_OBJECT")
public class SimpleObject extends DataObject implements java.io.Serializable{


private Integer id;
private String name;



@Override
@Id
@Column(name="SESSION_ID")
public Integer getId() {

return id;
}

@Override
public void setId(Integer id) {
this.id = id;

}




public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}





}





Now comes the part where I was a little foggy on. I needed to create a new DAO that utilized the new datasource using Spring annotations. Keep in mind that using @Autowire is great until two beans of the same type are defined in the same context. In that case, to select a particular one, you need to @Qualifier annotation.




@Repository("simpleObjectDAO")
public class SimpleObjectDAO extends GenericDAO{

protected SimpleObjectDAO() {
super(SessionInfo.class);

}


@Autowired// setHibernateTemplate is final in superclass so we cannot autowire it by default
@Override
public void setMyHibernateTemplate(@Qualifier("inMemoryHibernateTemplate") final HibernateTemplate template) {
setHibernateTemplate(template);
}

}




now, let's write a JUnit test to insure our new setup works.



public class SimpleObjectDAOTest {

@SpringBeanByType
SimpleObjectDAO simpleObjectDAO;




@Test
public void createRandomSimpleData() {




for (int i =0; i < 100; i++) { SimpleObject session = new SimpleObject (); session.setId(i); session.setName("Name: " + i); simpleObjectDAO.save(session); } } @Test public void findAllInformation() { Collection sessions = simpleInfoDAO.getAll();

log.debug("Session: " + sessions.size());

for (SimpleObject session : sessions) {

log.debug("ID: " + session.getId());
log.debug("Name: " + session.getBanknr());


}

}







There you have it, a quick in memory database. It is super fast as well it should be since it is all in memory. HSQLDB rocks. I think I will have plenty of more uses for this technique later on. Keep in mind that since my primary database is Oracle I could have done the same thing using a temporary table in Oracle and map my hibernate object to it. I like the HSQLDB approach better though, since it eliminates another database vendor dependency that I do not need hanging around my project. Another plus is that I can switch out my memory databases with a simple flick of the configuration. Man, do I love working with Spring and Hibernate. I think I mention this a lot.

3 comments:

Gilbert G said...

I liked H2 Database more than HSQLDB, It's actually faster

Bruce Snyder said...

I second that! H2 it has many more features and it's much faster.

mnuttall said...

Third it.

Post a Comment