採用 Spring 的 AbstractRoutingDataSource 實現運行期根據業務邏輯動態切換數據源,核心在於 ThreadLocal 綁定當前線程的數據源標識。
<beans ...>
<!-- 主數據源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="${jdbc.pool.maxActive}"/>
<property name="maxIdle" value="${jdbc.pool.maxIdle}"/>
<property name="minIdle" value="${jdbc.pool.minIdle}"/>
</bean>
<!-- 次數據源 -->
<bean id="dataSource_1" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url1}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="${jdbc.pool.maxActive}"/>
<property name="maxIdle" value="${jdbc.pool.maxIdle}"/>
<property name="minIdle" value="${jdbc.pool.minIdle}"/>
</bean>
<!-- 路由數據源:默認走 dataSource,通過 key 切換 -->
<bean id="multipleDataSource" class="cn.tomcat.quickstart.common.utils.MultipleDataSource">
<property name="defaultTargetDataSource" ref="dataSource"/>
<property name="targetDataSources">
<map><entry key="dataSource_1" value-ref="dataSource_1"/></map>
</property>
</bean>
<!-- 事務管理器綁定路由數據源 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="multipleDataSource"/>
</bean>
</beans>
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/quickstart?useUnicode=true&characterEncoding=utf-8 jdbc.url1=jdbc:mysql://localhost:3306/quickstart1?useUnicode=true&characterEncoding=utf-8 jdbc.username=root jdbc.password=password jdbc.pool.maxActive=50 jdbc.pool.maxIdle=10 jdbc.pool.minIdle=0
package cn.tomcat.quickstart.common.utils;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class MultipleDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<>();
public static void setDataSourceKey(String dataSource) {
dataSourceKey.set(dataSource);
}
@Override
protected Object determineCurrentLookupKey() {
return dataSourceKey.get(); // 返回當前線程綁定的 key
}
}
// 默認使用 dataSource
// 需要切換到次庫時:
MultipleDataSource.setDataSourceKey("dataSource_1");
try {
// 執行次庫操作
} finally {
// 清理或切回默認
MultipleDataSource.setDataSourceKey("dataSource");
}
InheritableThreadLocal 支援父子線程傳遞。multipleDataSource,否則事務邊界內可能切換數據源導致不一致。finally 中恢復,防止線程池復用時污染後續請求。