有時候我們想要實現動態選擇數據源的功能,即在進行數據庫操作時選擇對具體的某個數據源進行操作。這個功能我們利用Spring+Mybatis 即可實現。
1.DataSourceSwitcher
Spring 提供了一個 AbstractRoutingDataSource 抽象類來幫助我們實現動態數據源功能,我們可以自定義一個類 DataSourceSwitcher 並繼承 AbstractRoutingDataSource ,在 DataSourceSwitcher 類中實現三個方法 clearDataSource、determineCurrentLookupKey 和 setDataSourceKey 就行。
public class DataSourceSwitcher extends AbstractRoutingDataSource {
//因爲線程經常切換,所以將線程所分配的數據源存入 ThreadLocal中
private static final ThreadLocal<String> dataSourceKey=new ThreadLocal<>();
/**
* 清除 ThreadLocal 存儲的數據源
*/
public static void clearDataSource(){
dataSourceKey.remove();
}
/**
* 決定使用哪個數據庫
* @return
*/
@Override
protected Object determineCurrentLookupKey() {
String dataSource=dataSourceKey.get();
return dataSource;
}
/**
* 設置數據源
* @param dataSource
*/
public static void setDataSourceKey(String dataSource){
dataSourceKey.set(dataSource);
}
}
2.配置 spring-mybatis.xml
<!-- 引入配置文件-->
<context:property-placeholder location="classpath:druid.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${druid.username}" />
<property name="password" value="${druid.password}" />
<property name = "driverClassName" value = "${druid.driverClassName}" />
<!-- 初始化連接數量 -->
<property name="initialSize" value="${druid.initialSize}" />
<!-- 最小空閒連接數 -->
<property name="minIdle" value="${druid.minIdle}" />
<!-- 最大併發連接數 -->
<property name="maxActive" value="${druid.maxActive}" />
<!-- 配置獲取連接等待超時的時間 -->
<property name="maxWait" value="${druid.maxWait}" />
<!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連接,單位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="${druid.timeBetweenEvictionRunsMillis}" />
<!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="${druid.minEvictableIdleTimeMillis}" />
<property name="validationQuery" value="${druid.validationQuery}" />
<property name="testWhileIdle" value="${druid.testWhileIdle}" />
<property name="testOnBorrow" value="${druid.testOnBorrow}" />
<property name="testOnReturn" value="${druid.testOnReturn}" />
<!-- 打開PSCache,並且指定每個連接上PSCache的大小 如果用Oracle,則把poolPreparedStatements配置爲true,mysql可以配置爲false。 -->
<property name="poolPreparedStatements" value="${druid.poolPreparedStatements}" />
<property name="maxPoolPreparedStatementPerConnectionSize"
value="${druid.maxPoolPreparedStatementPerConnectionSize}"/>
</bean>
<!--主庫,master -->
<bean id="childDataSource1" parent="dataSource">
<property name="url" value="${druid.url1}"/>
</bean>
<!--從庫,mybatisTest-->
<bean id="childDataSource2" parent="dataSource">
<property name="url" value="${druid.url2}"/>
</bean>
<!-- 配置數據源選擇器 -->
<bean id="dataSourceSwitcher" class="com.datasource.switcher.DataSourceSwitcher">
<!-- 使用的數據源 -->
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="query1" value-ref="childDataSource1"/>
<entry key="update1" value-ref="childDataSource2"/>
</map>
</property>
<!-- 默認數據源 -->
<property name="defaultTargetDataSource" ref="childDataSource1"/>
</bean>
<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--<property name="plugins" ref="mybatisInterceptor"/>-->
<property name="dataSource" ref="dataSourceSwitcher" />
<!-- 選擇數據源的plguin -->
<property name="plugins" ref="dataSourceInterceptor"/>
<!-- 自動掃描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:com/log/web/mapper/*Mapper.xml"></property>
</bean>
<!-- DAO接口所在包名,Spring會自動查找其下的類 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.log.web" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
<!-- (事務管理)transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceSwitcher" />
</bean>
配置多個庫:
<!--主庫,master -->
<bean id="childDataSource1" parent="dataSource">
<property name="url" value="${druid.url1}"/>
</bean>
<!--從庫,mybatisTest-->
<bean id="childDataSource2" parent="dataSource">
<property name="url" value="${druid.url2}"/>
</bean>
配置數據源選擇器,在 targetDataSources 中配置將要使用的數據庫,key值用來選擇對應的數據庫
<!-- 配置數據源選擇器 -->
<bean id="dataSourceSwitcher" class="com.datasource.switcher.DataSourceSwitcher">
<!-- 使用的數據源 -->
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="query1" value-ref="childDataSource1"/>
<entry key="update1" value-ref="childDataSource2"/>
</map>
</property>
<!-- 默認數據源 -->
<property name="defaultTargetDataSource" ref="childDataSource1"/>
</bean>
3.在調用方法時傳入想要使用的數據庫 key 值,即 targetDataSources 中配置的數據庫對應的 key 值來選擇數據庫。
總結:使用Spring+Mybatis 來實現動態選擇數據源就完成了!我們與常規的Spring+Mybatis 不同的只是增加了一個DataSourceSwitcher 類,並在 spring-mybatis.xml 中聲明 DataSourceSwitcher 和使用到的多個 dataSource,並在 SqlSessionFactory 和 DataSourceTransactionManager 的 dataSource 引用聲明的 DataSourceSwitcher