Hi all,
I am currently working on a webservice that under the hood needs to provide data from/to several unterlying databases.
To achieve that I am using a DAOs with a hibernateTemplate. The all inherit from a base class which looks like this
Now in order to serve various databases, databse selection based on the incoming request, I was playing around with AbstractRoutingDatasource. MY hibernate configuration to achieve that looks like this.Code:public abstract class BaseCrudDao<T extends Serializable> implements BaseDao<T> { private static final Logger LOGGER = Logger.getLogger(BaseCrudDao.class); protected HibernateTemplate hibernateTemplate; protected Class<T> clazz; public BaseCrudDao(Class<T> clazz) { super(); this.clazz = clazz; } /** * * @param sessionFactory */ @Autowired public void initializeDao(SessionFactory sessionFactory) { hibernateTemplate = new HibernateTemplate(sessionFactory); } .... }
Now this seems a bit odd to me, first off all only the default datasource is initialized when the session Factory is instantiated. I get the reason why this is happening, still this is a unwanted side-effect.Code:<beans> ... <bean id="managingDataSource" class="test.DatabaseRoutingDataSource"> <property name="targetDataSources"> <map key-type="java.lang.String"> <entry key="AX1" value-ref="childDataSource"/> <entry key="AX2" value-ref="childDataSource2"/> </map> </property> <property name="defaultTargetDataSource" ref="childDataSource" /> </bean> <bean id="parentDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" abstract="true"> <property name="driverClass" value="${jdbc.driver.classname}" /> </bean> <bean id="childDataSource" parent="parentDataSource" destroy-method="close"> <property name="jdbcUrl" value="${jdbc.ax1.url}" /> <property name="user" value="${jdbc.ax1.username}" /> <property name="password" value="${jdbc.ax1.password}" /> </bean> <bean id="childDataSource2" parent="parentDataSource" destroy-method="close"> <property name="jdbcUrl" value="${jdbc.ax2.url}" /> <property name="user" value="${jdbc.ax2.username}" /> <property name="password" value="${jdbc.ax2.password}" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="managingDataSource" /> <property name="packagesToScan" value="test.ws" /> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">${jdbc.hibernate.dialect}</prop> <prop key="hibernate.hbm2ddl.auto">${jdbc.hibernate.hbm2ddl.auto}</prop> <prop key="hibernate.show_sql">${jdbc.hibernate.showSql}</prop> </props> </property> </bean> ... </beans>
Secondly it feels a bit off when sessions from different datasources are provided by one SessionFactory, as all the hibernate configuration, intended for a single database instance is applied over all datasources, incl. e.g. the session count etc.
So I wanted to implement a wrapper that implements the SessionFactory interface that more or less provides the AbstractRoutingDataSource functionality and looks as follows:
and changes my hibernate-configuration accordingly:Code:public class DatabaseRoutingSessionFactory implements SessionFactory { /** * */ private static final long serialVersionUID = 2257846544223138903L; private static final ThreadLocal<String> systemNameHolder = new ThreadLocal<String>(); private Map<String, SessionFactory> sessionFactories; /** * * @param systemName */ public synchronized static void setSystemName(String systemName) { systemNameHolder.set(systemName); } /** * * @return */ public synchronized static String getSystemName() { return systemNameHolder.get(); } /** * */ public synchronized static void clearSystemName() { systemNameHolder.remove(); } /** * @return the sessionFactories */ public synchronized Map<String, SessionFactory> getSessionFactories() { return sessionFactories; } /** * @param sessionFactories * the sessionFactories to set */ public synchronized void setSessionFactories(Map<String, SessionFactory> sessionFactories) { this.sessionFactories = sessionFactories; } @Override public synchronized Reference getReference() throws NamingException { return sessionFactories.get(getSystemName()).getReference(); } @Override public synchronized void close() throws HibernateException { sessionFactories.get(getSystemName()).close(); } //remaining implementation of SessionFactory interface .... }
Do you have any ideas or negative implications I am missing out on?? Maybe even a Standard Spring solution exists for this problem?? Any input and help is more than appreciated!Code:<beans> .... <bean id="managingSessionFactory" class=test.DatabaseRoutingSessionFactory"> <property name="sessionFactories"> <map key-type="java.lang.String" value-type="org.hibernate.SessionFactory"> <entry key="AX1" value-ref="sessionFactory1" /> <entry key="AX2" value-ref="sessionFactory2" /> </map> </property> </bean> <bean id="childDataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.driver.classname}" /> <property name="jdbcUrl" value="${jdbc.ax1.url}" /> <property name="user" value="${jdbc.ax1.username}" /> <property name="password" value="${jdbc.ax1.password}" /> </bean> <bean id="childDataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.driver.classname}" /> <property name="jdbcUrl" value="${jdbc.ax2.url}" /> <property name="user" value="${jdbc.ax2.username}" /> <property name="password" value="${jdbc.ax2.password}" /> </bean> <bean id="parentSessionFactory" abstract="true"> <property name="packagesToScan" value="test" /> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">${jdbc.hibernate.dialect}</prop> <prop key="hibernate.hbm2ddl.auto">${jdbc.hibernate.hbm2ddl.auto}</prop> <prop key="hibernate.show_sql">${jdbc.hibernate.showSql}</prop> </props> </property> </bean> <bean id="sessionFactory1" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" autowire-candidate="false"> <property name="dataSource" ref="childDataSource1" /> </bean> <bean id="sessionFactory2" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" autowire-candidate="false"> <property name="dataSource" ref="childDataSource2" /> </bean> ... </beans>
Thanks in advance!
Iulius


Reply With Quote
