Spring/Hibernate: Multiple Datasources Every once in a while, there is a need for my web application to talk to more than one database / datasource. In order to accomplish this for 2 datasources, the following needs to happen:
1. In your Spring application context file, you need to add a new data source:
<beans:bean id=”dataSource”class=”org.springframework.jdbc.datasource.DriverManagerDataSource”> <beans:property name=”driverClassName” value=”${db.driver}” /> <beans:property name=”url” value=”${db.url}” /> <beans:property name=”username” value=”${db.username}” /> <beans:property name=”password” value=”${db.password}” /> </beans:bean>
<beans:bean id=”dataSource2″class=”org.springframework.jdbc.datasource.DriverManagerDataSource”> <beans:property name=”driverClassName” value=”${db2.driver}” /> <beans:property name=”url” value=”${db2.url}” /> <beans:property name=”username” value=”${db2.username}” /> <beans:property name=”password” value=”${db2.password}” /> </beans:bean>
2. Next, make sure you have 2 session factories:
<beans:bean id=”sessionFactory”class=”org.springframework.orm.hibernate4.LocalSessionFactoryBean”> <beans:property name=”packagesToScan”> <beans:list> <beans:value>com.yourcompany.dto.*</beans:value> </beans:list> </beans:property> <beans:property name=”dataSource”> <beans:ref bean=”dataSource” /> </beans:property> <beans:property name=”configLocation”> <beans:value>classpath:hibernate.cfg.xml</beans:value> </beans:property> <beans:property name=”namingStrategy” ref=”namingStrategy” /> </beans:bean>
<beans:bean id=”sessionFactory2″class=”org.springframework.orm.hibernate4.LocalSessionFactoryBean”> <beans:property name=”packagesToScan”> <beans:list> <beans:value>com.yourcompany.otherdtos.*</beans:value> </beans:list> </beans:property> <beans:property name=”dataSource”> <beans:ref bean=”dataSource2″ /> </beans:property> <beans:property name=”configLocation”> <beans:value>classpath:hibernate.cfg.xml</beans:value> </beans:property> <beans:property name=”namingStrategy” ref=”namingStrategy” /> </beans:bean>
3. Next, make sure you have 2 transaction managers:
<tx:annotation-driven/>
<beans:bean id=”transactionManager”class=”org.springframework.orm.hibernate4.HibernateTransactionManager”> <beans:property name=”sessionFactory” ref=”sessionFactory” /> <beans:qualifier value=”transactionManager”/> </beans:bean>
<beans:bean id=”transactionManager2″class=”org.springframework.orm.hibernate4.HibernateTransactionManager”> <beans:property name=”sessionFactory” ref=”sessionFactory2″ /> <beans:qualifier value=”transactionManager2″/> </beans:bean>
4. Next move to your web.xml. If you are using a OpenSessionInViewFilter, make sure you have a filter for each session factory:
<filter> <filter-name>hibernateFilter</filter-name> <filter-class> org.springframework.orm.hibernate4.support.OpenSessionInViewFilter </filter-class> <init-param> <param-name>sessionFactoryBeanName</param-name> <param-value>sessionFactory</param-value> </init-param> </filter>
<filter> <filter-name>hibernateFilter2</filter-name> <filter-class> org.springframework.orm.hibernate4.support.OpenSessionInViewFilter </filter-class> <init-param> <param-name>sessionFactoryBeanName</param-name> <param-value>sessionFactory2</param-value> </init-param> </filter>
<filter-mapping> <filter-name>hibernateFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
<filter-mapping> <filter-name>hibernateFilter2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
5. Now it is time to dig into your Java code. We will focus on your database layer code, which will be in your DAO classes. The code below references a specific session factory and a specific transaction manager. Remember, your session factory references a specific datasource, and your transaction manager manages a specific session factory. You need to be able to distinguish between your different session factories and transaction managers. In order to do this, we use the @Qualifier annotation for session factory to specify the bean id of the session factory you want to use. For transactions, you need to pass the qualifier you gave your transaction manager in your application context. Here is some sample code that retrieves some data and prints to console:
import java.util.List;
import org.hibernate.Query; import org.hibernate.SessionFactory; import com.yourcompany.dto.State; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional;
@Repository @Transactional(“transactionManager2″) public class TestDao {
@Autowired @Qualifier(“sessionFactory2″) SessionFactory sessionFactory;
public void test() { Query query = sessionFactory.getCurrentSession().createQuery(“from State”); List<State> states = (List<State>) query.list(); for (State state : states) { System.out.println(state.getTitle()); } }
}
You can now specify on a DAO by DAO basis which data source you would like to point to.
|