spring动态创建,加载,使用多数据源
在大物流可视化中,因为要源数据复杂,需要使用多个数据源。不是配置多个数据源,而是如何灵活动态的切换数据源。例如在ssm项目中,我们在spring配置中往往是配置一个datasource来连接数据库,然后绑定sessionFactory,在dao层代码中在指定sessionFactory来进行数据库操作
正如上图所示,每一块都是绑定死的,如果是多个数据源,也只能是下图的方式。
可以看出在Dao层代码中写死了两个sessionFactory,这样日后如果在多一个数据源,还要改代码添加一个SessionFactory,显然这并不符合开闭原则。
那么正确的做法应该是
思路:
配置 parentDataSource 的父bean.再配置多个数据源继承这个父bean,对driverClass,url,username,password,等数据源连接参数进行各自的重写。例如 mySqlDataSource ,在 DataSources bean中注入所有要切换的数据源,并且设置默认的数据源。
spring-mybatis.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" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
">
<!-- 数据源相同的内容 -->
<bean id="parentDataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<!-- 连接池最大使用连接数 -->
<property name="maxActive">
<value>20</value>
</property>
<!-- 初始化连接大小 -->
<property name="initialSize">
<value>1</value>
</property>
<!-- 获取连接最大等待时间 -->
<property name="maxWait">
<value>60000</value>
</property>
<!-- 连接池最大空闲 -->
<property name="maxIdle">
<value>20</value>
</property>
<!-- 连接池最小空闲 -->
<property name="minIdle">
<value>3</value>
</property>
<!-- 自动清除无用连接 -->
<property name="removeAbandoned">
<value>true</value>
</property>
<!-- 清除无用连接的等待时间 -->
<property name="removeAbandonedTimeout">
<value>180</value>
</property>
<!-- 连接属性 -->
<property name="connectionProperties">
<value>clientEncoding=UTF-8</value>
</property>
</bean>
<!-- start以下配置各个数据源的特性 -->
<bean parent="parentDataSource" id="DvDataSource">
<property name="driverClassName">
<value>${jdbc_driverClassName}</value>
</property>
<property name="url">
<value>${dv_url}</value>
</property>
<property name="username">
<value>${jdbc_username}</value>
</property>
<property name="password">
<value>${jdbc_password}</value>
</property>
</bean>
<bean parent="parentDataSource" id="OcDataSource">
<property name="driverClassName">
<value>${jdbc_driverClassName}</value>
</property>
<property name="url">
<value>${oc_url}</value>
</property>
<property name="username">
<value>${jdbc_username}</value>
</property>
<property name="password">
<value>${jdbc_password}</value>
</property>
</bean>
<bean parent="parentDataSource" id="InDataSource">
<property name="driverClassName">
<value>${jdbc_driverClassName}</value>
</property>
<property name="url">
<value>${in_url}</value>
</property>
<property name="username">
<value>${jdbc_username}</value>
</property>
<property name="password">
<value>${jdbc_password}</value>
</property>
</bean>
<bean parent="parentDataSource" id="WcDataSource">
<property name="driverClassName">
<value>${jdbc_driverClassName}</value>
</property>
<property name="url">
<value>${wc_url}</value>
</property>
<property name="username">
<value>${jdbc_username}</value>
</property>
<property name="password">
<value>${jdbc_password}</value>
</property>
</bean>
<bean parent="parentDataSource" id="AcDataSource">
<property name="driverClassName">
<value>${jdbc_driverClassName}</value>
</property>
<property name="url">
<value>${ac_url}</value>
</property>
<property name="username">
<value>${jdbc_username}</value>
</property>
<property name="password">
<value>${jdbc_password}</value>
</property>
</bean>
<bean class="org.blue.ex.test.DynamicDataSource" id="dataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry value-ref="DvDataSource" key="DV"></entry>
<entry value-ref="OcDataSource" key="OC"></entry>
<entry value-ref="InDataSource" key="IN"></entry>
<entry value-ref="WcDataSource" key="WC"></entry>
<entry value-ref="AcDataSource" key="AC"></entry>
</map>
</property>
<property name="defaultTargetDataSource" ref="DvDataSource" ></property>
</bean>
<!-- myBatis文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 自动扫描entity目录, 省掉Configuration.xml里的手工配置 -->
<property name="mapperLocations" value="classpath:mapper/*.xml" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="org.blue.ex.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 注解方式配置事物 -->
<!-- <tx:annotation-driven transaction-manager="transactionManager" /> -->
<!-- 拦截器方式配置事物 -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="select*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- Spring aop事务管理 -->
<aop:config>
<aop:pointcut id="transactionPointcut"
expression="execution(* org.blue.ex.service..*Impl.*(..))" />
<aop:advisor pointcut-ref="transactionPointcut"
advice-ref="transactionAdvice" />
</aop:config>
</beans>
DataSourceConst.java
package org.blue.ex.test;
/**
* 动态配置多数据源
* 数据源的名称常量类
* @author LONGHUI_LUO
*
*/
public class DataSourceConst {
/**
* 展示数据库
*/
public static final String DV="DV";
/**
* 订单数据库
*/
public static final String OC="OC";
/**
* 主数据库
*/
public static final String IN="IN";
/**
* 仓库数据库
*/
public static final String WC="WC";
/**
* 订单预警数据库
*/
public static final String AC="AC";
}
DataSourceContextHolder.java
package org.blue.ex.test;
/**
* 获得和设置上下文环境 主要负责改变上下文数据源的名称
*
* @author liujg
*
*/
public class DataSourceContextHolder {
private static final ThreadLocal contextHolder = new ThreadLocal(); // 线程本地环境
/**
* 设置数据源类型
* @param dataSourceType
*/
public static void setDataSourceType(String dataSourceType) {
contextHolder.set(dataSourceType);
}
/**
* 获取数据源类型
* @return
*/
public static String getDataSourceType() {
return (String) contextHolder.get();
}
/**
* 清除数据源类型
*/
public static void clearDataSourceType() {
contextHolder.remove();
}
}
DynamicDataSource
package org.blue.ex.test;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* 建立动态数据源
*
* @author LONGHUI_LUO
*
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
protected Object determineCurrentLookupKey() {
// 在进行DAO操作前,通过上下文环境变量,获得数据源的类型
return DataSourceContextHolder.getDataSourceType();
}
}