Skip to content

Data sources

zenbones edited this page Dec 7, 2011 · 8 revisions

Data Sources

We're going to describe the Spring-based setup of your database using a Hibernate example, and continue using Hibernate as an example under the The DAO Framework. Translating these examples for use with other ORM systems should be relatively straightforward given a familiarity with this material.

Each data source in your system will represent a set of connections to a single schema within your database manager (Mysql, Oracle, Postgress, etc.). That schema may have multiple tables over which you may run any set of SQL operations. Each data source will have a name, and you'll need to be very consistent in that name's usage. We'll start with the basic setup for the ORM, in this case Hibernate...

hibernate.xml

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

   <!-- Collect Spring Initialized Hibernate Resources -->
   <bean class="org.smallmind.persistence.orm.spring.hibernate.HibernateAnnotationSeekingBeanFactoryPostProcessor">
      <property name="markedAnnotations">
         <list>
            <value>javax.persistence.Entity</value>
         </list>
      </property>
   </bean>

   <bean class="org.smallmind.persistence.orm.spring.hibernate.HibernateFileSeekingBeanFactoryPostProcessor"/>

   <bean id="statisticsFactory" class="org.smallmind.persistence.statistics.ThreadLocalStatisticsFactory">
      <constructor-arg index="0" value="${orm.statistics}"/>
   </bean>

   <bean id="stringConverterFactory" class="org.smallmind.persistence.model.type.converter.DefaultStringConverterFactory"/>

   <bean id="persistence" class="org.smallmind.persistence.Persistence" init-method="register">
      <constructor-arg index="0">
         <bean class="org.smallmind.persistence.statistics.ThreadLocalStatisticsFactory">
            <constructor-arg index="0" value="${orm.statistics}"/>
         </bean>
      </constructor-arg>
      <constructor-arg index="1">
         <bean class="org.smallmind.persistence.model.type.converter.DefaultStringConverterFactory"/>
      </constructor-arg>
   </bean>

   <!-- AspectJ Transaction Management -->
   <bean id="transactionManagerAspect" class="org.smallmind.persistence.orm.aop.TransactionalAspect" factory-method="aspectOf"/>

</beans>

This setup will seek out Java classes marked as Hibernate Entities via JPA annotation (@Entity), or configured via xml in '.hbm.xml' files, so long as those Entities are themselves Spring configured. Also included is the setup for tracking orm/cache usage and timing statistics, and transparent session/transaction management via annotations (@Transactional, @NonTransactional), see The DAO Framework.

With this base setup in hand, we can go on to setup all the particulars for a single data source, aptly named 'foo'...

<data source name>-hibernate.xml

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

  <import resource="classpath:com/<my company>/<persistence module>/hibernate.xml"/>

  <!-- Connection Pooling -->
  <bean id="fooConnectionInstanceFactory" class="org.smallmind.persistence.orm.sql.pool.DriverManagerConnectionInstanceFactory">
    <constructor-arg index="0" value="${jdbc.driver.classname}"/>
    <constructor-arg index="1" value="${jdbc.url.foo}"/>
    <constructor-arg index="2" value="${jdbc.username.foo}"/>
    <constructor-arg index="3" value="${jdbc.password.foo}"/>
    <property name="validationQuery" value="${jdbc.validation.statement}"/>
  </bean>

  <bean id="fooDBPool" class="org.smallmind.quorum.pool.connection.ConnectionPool" init-method="startup" destroy-method="shutdown">
    <constructor-arg index="0" value="dbPool"/>
    <constructor-arg index="1" ref="fooConnectionInstanceFactory"/>
    <property name="testOnAcquire" value="${jdbc.pool.acquire.test}"/>
    <property name="initialPoolSize" value="${jdbc.pool.size.min}"/>
    <property name="minPoolSize" value="${jdbc.pool.size.min}"/>
    <property name="maxPoolSize" value="${jdbc.pool.size.max}"/>
    <property name="acquireWaitTimeMillis" value="1000"/>
    <property name="connectionTimeoutMillis" value="500"/>
    <property name="maxIdleTimeSeconds" value="300"/>
    <property name="maxLeaseTimeSeconds" value="7200"/>
  </bean>

  <bean id="fooPooledDataSource" class="org.smallmind.persistence.orm.sql.pool.PooledDataSource">
    <constructor-arg index="0" value="foo"/>
    <constructor-arg index="1" ref="fooDBPool"/>
  </bean>

  <!-- Session and Transaction -->
  <bean id="fooSessionFactory" class="org.smallmind.persistence.orm.spring.hibernate.AnnotationAwareLocalSessionFactoryBean">
    <property name="dataSourceKey" value="foo"/>
    <property name="dataSource" ref="fooPooledDataSource"/>
    <property name="mappingLocations">
      <bean class="org.smallmind.persistence.orm.spring.hibernate.HibernateFileSeekingFactoryBean">
        <property name="dataSourceKey" value="foo"/>
      </bean>
    </property>
    <property name="hibernateProperties">
      <value>
        hibernate.dialect=${hibernate.dialect}
        hibernate.hbm2ddl.auto=${hibernate.hbm2ddl.auto}
        hibernate.bytecode.use_reflection_optimizer=true
        hibernate.id.new_generator_mappings=true
        hibernate.connection.isolation=${hibernate.connection.isolation}
        hibernate.connection.autocommit=${hibernate.connection.autocommit}
        hibernate.jdbc.use_scrollable_resultset=true
        hibernate.jdbc.batch_size=${hibernate.jdbc.batch_size}
        hibernate.query.substitutions=true 1, false 0
        hibernate.show_sql=${hibernate.show_sql}
        hibernate.format_sql=${hibernate.format_sql}
        hibernate.use_sql_comments=false
        hibernate.generate_statistics=false
        hibernate.cache.use_second_level_cache=${hibernate.cache.use_second_level_cache}
        hibernate.cache.use_query_cache=false
        hibernate.cache.use_minimal_puts=true
        hibernate.cache.provider_class=${hibernate.cache.provider_class}
      </value>
    </property>
  </bean>

  <!--Proxy Session-->
  <bean id="fooProxySession" class="org.smallmind.persistence.orm.hibernate.HibernateProxySession" init-method="register">
    <constructor-arg index="0" value="foo"/>
    <constructor-arg index="1" ref="fooSessionFactory"/>
    <constructor-arg index="2" value="true"/>
    <constructor-arg index="3" value="true"/>
  </bean>

</beans>

We've used the SmallMind connection pooling framework in this file, but this can be substituted with the Spring configuration for the connection pool of your choice. The SmallMind pool happens to be fast, especially in a multi-threaded environment under load, is relatively easy to setup, has JMX-based management extensions, and if you've gotten this far, then you already have the jar file and the source code.

We've also used a bunch of dot-notated variable substitutions. You can replace these by hard coded values, or swap some of the hard coded values for further variable substitutions. The variables should be defined within the property file hierarchy (see Property Files), and any Spring setup should begin by loading foundation.xml (and hopefully logging.xml as well).