Spring2.0.1以后的版本已经支持配置多数据源,并且可以在运行的时候动态加载不同的数据源。通过继承AbstractRoutingDataSource就可以实现多数据源的动态转换。目前做的项目就是需要访问12个数据源,每个数据源的表结构都是相同的,所以要求数据源的变动对于编码人员来说是透明,也就是说同样SQL语句在不同的环境下操作的数据库是不一样的。具体的配置如下:
一、首先需要写一个静态的键值对照类:
package cn.sunline.suncard.sde.dp.db;
public class DataSourceMap {
public static final String acd="ACD";
public static final String trm= "TRM";
}
这个类主要在使用的时候当作获得数据源的标志使用。
二、建立一个获得和设置上下文的类:
package cn.sunline.suncard.sde.dp.db;
/**
* 数据源容器类
* @author tpf
* @version 1.0 2012-8-27
* @see [相关类/方法]
* @since [产品/模块版本]
*/
public class CustomerContextHolder {
/**
* 数据库连接配置容器
*/
private static ThreadLocal contextHolder = new ThreadLocal();
public static void setCustomerType(String customerType) {
contextHolder.set(customerType);
}
public static String getCustomerType() {
return (String) contextHolder.get();
}
public static void clearCustomerType() {
contextHolder.remove();
}
/**
* 数据源容器类
* @author tpf
* @version 1.0 2012-8-27
* @see [相关类/方法]
* @since [产品/模块版本]
*/
public class CustomerContextHolder {
/**
* 数据库连接配置容器
*/
private static ThreadLocal contextHolder = new ThreadLocal();
public static void setCustomerType(String customerType) {
contextHolder.set(customerType);
}
public static String getCustomerType() {
return (String) contextHolder.get();
}
public static void clearCustomerType() {
contextHolder.remove();
}
}
这个主要负责设置上下文环境和获得上下文环境。
三、建立动态数据源类,这个类必须继承AbstractRoutingDataSource:package cn.sunline.suncard.sde.dp.db;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* 动态数据源
* @author tpf
* @version 1.0 2012-8-27
* @see [相关类/方法]
* @since [产品/模块版本]
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
/* (non-Javadoc)
* @see org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource#determineCurrentLookupKey()
*/
@Override
protected Object determineCurrentLookupKey() {
String customerType = "";
if(CustomerContextHolder.getCustomerType() != null) {
customerType = CustomerContextHolder.getCustomerType().toString();
}
return customerType;
}
}
这个类实现了determineCurrentLookupKey方法,该方法返回一个Object,一般是返回字符串,也可以是枚举类型。该方法中直接使用了CustomerContextHolder.getCustomerType()方法获得上下文环境并直接返回。
四、编写spring的配置文件配置数据源
<bean id="hibernateInterceptor" class="cn.sunline.suncard.sde.dp.interceptor.HibernateInterceptor"></bean>
<bean id="lobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" lazy-init="true" />
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
dependency-check="none">
<property name="fileEncoding" value="UTF-8" />
<property name="locations">
<list>
<value>/WEB-INF/config/jdbc.properties</value>
</list>
</property>
</bean>
<!--
<bean id="acdDataSource" class="cn.sunline.suncard.sde.dp.db.ProxoolDataSourceImpl">
<property name="driver">
<value>${acdDataSource.driverClassName}</value>
</property>
<property name="driverUrl">
<value>${acdDataSource.url}</value>
</property>
<property name="user">
<value>${acdDataSource.username}</value>
</property>
<property name="password">
<value>${acdDataSource.password}</value>
</property>
<property name="prototypeCount">
<value>${acdDataSource.protoconn}</value>
</property>
<property name="maximumConnectionCount">
<value>${acdDataSource.maxconn}</value>
</property>
<property name="minimumConnectionCount">
<value>${acdDataSource.minconn}</value>
</property>
<property name="simultaneousBuildThrottle">
<value>${acdDataSource.simultaneousBuildThrottle}</value>
</property>
<property name="trace">
<value>false</value>
</property>
<property name="verbose">
<value>true</value>
</property>
</bean>
<bean id="trmDataSource" class="cn.sunline.suncard.sde.dp.db.ProxoolDataSourceImpl">
<property name="driver">
<value>${trmDataSource.driverClassName}</value>
</property>
<property name="driverUrl">
<value>${trmDataSource.url}</value>
</property>
<property name="user">
<value>${trmDataSource.username}</value>
</property>
<property name="password">
<value>${trmDataSource.password}</value>
</property>
<property name="prototypeCount">
<value>${trmDataSource.protoconn}</value>
</property>
<property name="maximumConnectionCount">
<value>${trmDataSource.maxconn}</value>
</property>
<property name="minimumConnectionCount">
<value>${trmDataSource.minconn}</value>
</property>
<property name="simultaneousBuildThrottle">
<value>${trmDataSource.simultaneousBuildThrottle}</value>
</property>
<property name="trace">
<value>false</value>
</property>
<property name="verbose">
<value>true</value>
</property>
</bean>
-->
<bean id="acdDataSource2" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>${acdDataSource.driverClassName}</value>
</property>
<property name="url">
<value>${acdDataSource.url}</value>
</property>
<property name="username">
<value>${acdDataSource.username}</value>
</property>
<property name="password">
<value>${acdDataSource.password}</value>
</property>
</bean>
<bean id="trmDataSource2" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>${trmDataSource.driverClassName}</value>
</property>
<property name="url">
<value>${trmDataSource.url}</value>
</property>
<property name="username">
<value>${trmDataSource.username}</value>
</property>
<property name="password">
<value>${trmDataSource.password}</value>
</property>
</bean>
<bean id="dataSource" class="cn.sunline.suncard.sde.dp.db.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="ACD" value-ref="acdDataSource2"/>
<entry key="TRM" value-ref="trmDataSource2"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="acdDataSource2"/>
</bean>
<!-- sessionFactory配置开始 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="lobHandler" ref="lobHandler"/>
<!-- <property name="configLocation" value="/WEB-INF/config/hibernate.cfg.xml"/> -->
<property name="entityInterceptor">
<ref bean="hibernateInterceptor"/>
</property>
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.connection.useUnicode">true</prop>
<prop key="hibernate.connection.characterEncoding">UTF-8</prop>
<prop key="hibernate.connection.release_mode">auto</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>cn/sunline/suncard/sde/dp/hbm/DpStrategy.hbm.xml</value>
<value>cn/sunline/suncard/sde/dp/hbm/TrmUser.hbm.xml</value>
<value>cn/sunline/suncard/sde/dp/hbm/DpDatapart.hbm.xml</value>
<value>cn/sunline/suncard/sde/dp/hbm/TrmAuthtrxnlog.hbm.xml</value>
</list>
</property>
</bean>
<!--配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<!--配置事务管理的特性(隔离级别,传播特性...) -->
<tx:advice id="transAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="find*" read-only="true"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="query*" read-only="true"/>
<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="read*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="del*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="edit*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="id*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="*" propagation="REQUIRED" read-only="true" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<!--配置多数据源的事务拦截器-->
<aop:config>
<aop:pointcut expression="execution(* cn.sunline.suncard.sde.dp.dao.impl.*.*(..))" id="managerpc"/>
<aop:advisor advice-ref="transAdvice" pointcut-ref="managerpc"/>
<bean id="lobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" lazy-init="true" />
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
dependency-check="none">
<property name="fileEncoding" value="UTF-8" />
<property name="locations">
<list>
<value>/WEB-INF/config/jdbc.properties</value>
</list>
</property>
</bean>
<!--
<bean id="acdDataSource" class="cn.sunline.suncard.sde.dp.db.ProxoolDataSourceImpl">
<property name="driver">
<value>${acdDataSource.driverClassName}</value>
</property>
<property name="driverUrl">
<value>${acdDataSource.url}</value>
</property>
<property name="user">
<value>${acdDataSource.username}</value>
</property>
<property name="password">
<value>${acdDataSource.password}</value>
</property>
<property name="prototypeCount">
<value>${acdDataSource.protoconn}</value>
</property>
<property name="maximumConnectionCount">
<value>${acdDataSource.maxconn}</value>
</property>
<property name="minimumConnectionCount">
<value>${acdDataSource.minconn}</value>
</property>
<property name="simultaneousBuildThrottle">
<value>${acdDataSource.simultaneousBuildThrottle}</value>
</property>
<property name="trace">
<value>false</value>
</property>
<property name="verbose">
<value>true</value>
</property>
</bean>
<bean id="trmDataSource" class="cn.sunline.suncard.sde.dp.db.ProxoolDataSourceImpl">
<property name="driver">
<value>${trmDataSource.driverClassName}</value>
</property>
<property name="driverUrl">
<value>${trmDataSource.url}</value>
</property>
<property name="user">
<value>${trmDataSource.username}</value>
</property>
<property name="password">
<value>${trmDataSource.password}</value>
</property>
<property name="prototypeCount">
<value>${trmDataSource.protoconn}</value>
</property>
<property name="maximumConnectionCount">
<value>${trmDataSource.maxconn}</value>
</property>
<property name="minimumConnectionCount">
<value>${trmDataSource.minconn}</value>
</property>
<property name="simultaneousBuildThrottle">
<value>${trmDataSource.simultaneousBuildThrottle}</value>
</property>
<property name="trace">
<value>false</value>
</property>
<property name="verbose">
<value>true</value>
</property>
</bean>
-->
<bean id="acdDataSource2" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>${acdDataSource.driverClassName}</value>
</property>
<property name="url">
<value>${acdDataSource.url}</value>
</property>
<property name="username">
<value>${acdDataSource.username}</value>
</property>
<property name="password">
<value>${acdDataSource.password}</value>
</property>
</bean>
<bean id="trmDataSource2" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>${trmDataSource.driverClassName}</value>
</property>
<property name="url">
<value>${trmDataSource.url}</value>
</property>
<property name="username">
<value>${trmDataSource.username}</value>
</property>
<property name="password">
<value>${trmDataSource.password}</value>
</property>
</bean>
<bean id="dataSource" class="cn.sunline.suncard.sde.dp.db.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="ACD" value-ref="acdDataSource2"/>
<entry key="TRM" value-ref="trmDataSource2"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="acdDataSource2"/>
</bean>
<!-- sessionFactory配置开始 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="lobHandler" ref="lobHandler"/>
<!-- <property name="configLocation" value="/WEB-INF/config/hibernate.cfg.xml"/> -->
<property name="entityInterceptor">
<ref bean="hibernateInterceptor"/>
</property>
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.connection.useUnicode">true</prop>
<prop key="hibernate.connection.characterEncoding">UTF-8</prop>
<prop key="hibernate.connection.release_mode">auto</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>cn/sunline/suncard/sde/dp/hbm/DpStrategy.hbm.xml</value>
<value>cn/sunline/suncard/sde/dp/hbm/TrmUser.hbm.xml</value>
<value>cn/sunline/suncard/sde/dp/hbm/DpDatapart.hbm.xml</value>
<value>cn/sunline/suncard/sde/dp/hbm/TrmAuthtrxnlog.hbm.xml</value>
</list>
</property>
</bean>
<!--配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<!--配置事务管理的特性(隔离级别,传播特性...) -->
<tx:advice id="transAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="find*" read-only="true"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="query*" read-only="true"/>
<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="read*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="del*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="edit*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="id*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="*" propagation="REQUIRED" read-only="true" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<!--配置多数据源的事务拦截器-->
<aop:config>
<aop:pointcut expression="execution(* cn.sunline.suncard.sde.dp.dao.impl.*.*(..))" id="managerpc"/>
<aop:advisor advice-ref="transAdvice" pointcut-ref="managerpc"/>
</aop:config>
在项目中对于编码人员对多数据源的切换可以做成透明的,操作同样的dao,就可以访问不同的数据库了。