1、配置数据源
<!-- 阿里 druid数据库连接池 -->
<!-- 配置数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<!-- 数据库基本信息配置 -->
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="filters" value="${filters}" />
<!-- 最大并发连接数 -->
<property name="maxActive" value="${maxActive}" />
<!-- 初始化连接数量 -->
<property name="initialSize" value="${initialSize}" />
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="${maxWait}" />
<!-- 最小空闲连接数 -->
<property name="minIdle" value="${minIdle}" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" />
<property name="validationQuery" value="${validationQuery}" />
<property name="testWhileIdle" value="${testWhileIdle}" />
<property name="testOnBorrow" value="${testOnBorrow}" />
<property name="testOnReturn" value="${testOnReturn}" />
<property name="maxOpenPreparedStatements" value="${maxOpenPreparedStatements}" />
<!-- 打开removeAbandoned功能 -->
<property name="removeAbandoned" value="${removeAbandoned}" />
<!-- 1800秒,也就是30分钟 -->
<property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" />
<!-- 关闭abanded连接时输出错误日志 -->
<property name="logAbandoned" value="${logAbandoned}" />
</bean>
<!-- 配置数据源 -->
<bean id="tradeDataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<!-- 数据库基本信息配置 -->
<property name="url" value="${jdbc.trade.url}" />
<property name="username" value="${jdbc.trade.username}" />
<property name="password" value="${jdbc.trade.password}" />
<property name="driverClassName" value="${jdbc.trade.driverClassName}" />
<property name="filters" value="${filters}" />
<!-- 最大并发连接数 -->
<property name="maxActive" value="${maxActive}" />
<!-- 初始化连接数量 -->
<property name="initialSize" value="${initialSize}" />
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="${maxWait}" />
<!-- 最小空闲连接数 -->
<property name="minIdle" value="${minIdle}" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" />
<property name="validationQuery" value="${validationQuery}" />
<property name="testWhileIdle" value="${testWhileIdle}" />
<property name="testOnBorrow" value="${testOnBorrow}" />
<property name="testOnReturn" value="${testOnReturn}" />
<property name="maxOpenPreparedStatements" value="${maxOpenPreparedStatements}" />
<!-- 打开removeAbandoned功能 -->
<property name="removeAbandoned" value="${removeAbandoned}" />
<!-- 1800秒,也就是30分钟 -->
<property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" />
<!-- 关闭abanded连接时输出错误日志 -->
<property name="logAbandoned" value="${logAbandoned}" />
</bean>
2、配置统一管理的dynamicDataSource
<!--统一的dataSource-->
<bean id="dynamicDataSource" class="com.weather.framework.support.dao.DynamicDataSource" >
<property name="targetDataSources">
<map key-type="java.lang.String">
<!--通过不同的key决定用哪个dataSource-->
<entry value-ref="dataSource" key="dataSource"></entry>
<entry value-ref="tradeDataSource" key="tradeDataSource"></entry>
</map>
</property>
<!--设置默认的dataSource-->
<property name="defaultTargetDataSource" ref="dataSource">
</property>
</bean>
3、通过ThreadLocal来标识当前线程选择哪个datasource
package com.weather.framework.support.dao;
import org.apache.commons.lang.StringUtils;
public class CustomerContextHolder {
public static final String DATA_SOURCE = "dataSource";
public static final String TRADE_DATA_SOURCE = "tradeDataSource";
//用ThreadLocal来设置当前线程使用哪个dataSource
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static void setCustomerType(String customerType) {
contextHolder.set(customerType);
}
public static String getCustomerType() {
String dataSource = contextHolder.get();
if (!StringUtils.isEmpty(dataSource)){
if (dataSource.equals(TRADE_DATA_SOURCE)) {
return TRADE_DATA_SOURCE;
}else {
return DATA_SOURCE;
}
}else {
return DATA_SOURCE;
}
}
public static void clearCustomerType() {
contextHolder.remove();
}
}
4、dynamicDataSource需要继承AbstractRoutingDataSource,因为多个德鲁伊数据源已经加载完成,只需要通过AOP进行数据源的选择,从而达到数据源的切换。
package com.weather.framework.support.dao;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return CustomerContextHolder.getCustomerType();
}
}
5、aop事务控制
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dynamicDataSource"/>
</bean>
<!-- TransactionManager定义 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<tx:advice id="txAdvice-provider" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="create*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="merge*" propagation="REQUIRED"/>
<tx:method name="del*" propagation="REQUIRED"/>
<tx:method name="remove*" propagation="REQUIRED"/>
<tx:method name="put*" propagation="REQUIRED"/>
<tx:method name="process*" propagation="REQUIRED" />
<tx:method name="do*" propagation="REQUIRED" />
<tx:method name="query*" read-only="true"/>
<tx:method name="use*" read-only="true"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="count*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="list*" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:aspectj-autoproxy proxy-target-class="true" />
<aop:config expose-proxy="true">
<!-- 只对业务逻辑层实施事务 -->
<aop:pointcut id="transactionPointCut" expression="execution(* com.weather.*.activity.provider..*(..))" />
<aop:advisor pointcut-ref="transactionPointCut" advice-ref="txAdvice-provider" />
</aop:config>
至此,数据源配置成功,在执行某方法前,可以通过执行CustomerContextHolder.setCustomerType(“数据源Key”)进行数据源切换,也可以通过intercepter进行拦截。