在項目開發裡面,多資料源是最普遍不過的,一個項目使用多個資料庫是非常正常的,那麼這篇就是基于SSM架構去輕松實作使用多資料源的實戰場景。
基于SSM架構
開始,
首先準備2個不同的資料源(多個也行),在jdbc.properties:
#資料源 1
first_driverClass =com.mysql.jdbc.Driver
first_jdbcUrl=jdbc:mysql://localhost:3306/game_message?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
first_username=root
first_password=root
#資料源 2
second_driverClass=com.mysql.jdbc.Driver
second_jdbcUrl=jdbc:mysql://localhost:3306/web_slave?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
second_username=root
second_password=root
#定義初始連接配接數
initialSize=0
#定義最大連接配接數
maxActive=20
#定義最大空閑
maxIdle=20
#定義最小空閑
minIdle=1
#定義最長等待時間
maxWait=60000
然後在applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" 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.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd ">
<!-- ①:對com.springmvc包中的所有類進行掃描,以完成Bean建立和自動依賴注入的功能 -->
<context:component-scan base-package="com.springmvc"/>
<mvc:annotation-driven />
<!-- 靜态資源通路 -->
<!--如果webapp下你建立了檔案夾,想通路裡面的靜态資源,那麼就要在這配置一下-->
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/styles/" mapping="/styles/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
<!-- 開啟mvc注解 -->
<mvc:annotation-driven >
<!-- 處理responseBody 裡面日期類型 -->
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss" />
</bean>
</property>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- Configures the @Controller programming model
<mvc:annotation-driven />-->
<!-- ②:啟動Spring MVC的注解功能,完成請求和注解POJO的映射 -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="mappingJacksonHttpMessageConverter"/>
</list>
</property>
</bean>
<bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
<!-- 配置視圖解析器,把控制器的邏輯視訊映射為真正的視圖 -->
<!-- /WEB-INF/jsp/start.jsp -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- <context:property-placeholder location="classpath:db.properties"/> -->
<!--資料庫配置 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:jdbc.properties</value>
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true" />
</bean>
<!-- 配置第一個資料源 -->
<bean id="firstSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${first_driverClass}"/>
<property name="url" value="${first_jdbcUrl}"/>
<property name="username" value="${first_username}"/>
<property name="password" value="${first_password}"/>
<!-- 初始化連接配接大小 -->
<property name="initialSize" value="${initialSize}"></property>
<!-- 連接配接池最大數量 -->
<property name="maxActive" value="${maxActive}"></property>
<!-- 連接配接池最大空閑 -->
<property name="maxIdle" value="${maxIdle}"></property>
<!-- 連接配接池最小空閑 -->
<property name="minIdle" value="${minIdle}"></property>
<!-- 擷取連接配接最大等待時間 -->
<property name="maxWait" value="${maxWait}"></property>
</bean>
<!-- 配置第二個資料源 -->
<bean id="secondSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${second_driverClass}"/>
<property name="url" value="${second_jdbcUrl}"/>
<property name="username" value="${second_username}"/>
<property name="password" value="${second_password}"/>
<!-- 初始化連接配接大小 -->
<property name="initialSize" value="${initialSize}"></property>
<!-- 連接配接池最大數量 -->
<property name="maxActive" value="${maxActive}"></property>
<!-- 連接配接池最大空閑 -->
<property name="maxIdle" value="${maxIdle}"></property>
<!-- 連接配接池最小空閑 -->
<property name="minIdle" value="${minIdle}"></property>
<!-- 擷取連接配接最大等待時間 -->
<property name="maxWait" value="${maxWait}"></property>
</bean>
<!--配置多資料源切換加載-->
<bean id="dataSource" class="com.springmvc.dynamicsource.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<!-- 指定lookupKey和與之對應的資料源,這裡的key可以自行定義,要切換資料庫的時候以key為辨別,不要寫錯 -->
<entry key="firstSource" value-ref="firstSource"></entry>
<entry key="secondSource" value-ref="secondSource"></entry>
</map>
</property>
<!-- 這裡可以指定預設的資料源 -->
<property name="defaultTargetDataSource" ref="firstSource" />
</bean>
<!-- 配置事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置會話工廠SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 資料源 -->
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis.xml" />
<property name="mapperLocations" value="classpath:sqlmap/*Mapper.xml"/>
<property name="typeAliasesPackage" value="com.springmvc.entity" />
</bean>
<!-- 在spring容器中配置mapper的掃描器産生的動态代理對象在spring的容器中自動注冊,bean的id就是mapper類名(首字母小寫)-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 指定掃描包的路徑,就是mapper接口的路徑,多個包中間以 半形逗號隔開 -->
<property name="basePackage" value="com.springmvc.dao"/>
<!-- 配置sqlSessionFactoryBeanName -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<!-- 攔截器 -->
<mvc:interceptors>
<!-- 國際化操作攔截器 如果采用基于(請求/Session/Cookie)則必需配置 -->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
</mvc:interceptors>
<!-- 定義無Controller的path<->view直接映射 -->
<!-- <mvc:view-controller path="/" view-name="redirect:/" /> -->
</beans>
然後是定義動态資料源,DynamicDataSource.java:
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* @Author : JCccc
* @CreateTime : 2019/8/15
* @Description :
**/
public class DynamicDataSource extends AbstractRoutingDataSource{
//定義動态資料源,內建spring提供的AbstractRoutingDataSource,實作determineCurrentLookupKey
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDataSource();
}
}
接着是動态切換資料源方法類,DynamicDataSourceHolder.java:
/**
* @Author : JCccc
* @CreateTime : 2019/8/15
* @Description :
**/
public class DynamicDataSourceHolder
{
private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal();
public static String getDataSource()
{
return (String)THREAD_DATA_SOURCE.get();
}
public static void setDataSource(String dataSource)
{
THREAD_DATA_SOURCE.set(dataSource);
}
public static void clearDataSource()
{
THREAD_DATA_SOURCE.remove();
}
}
到這,多資料源已經實作了,我們在切換資料源,使用的時候隻需要用以下這行代碼進行切換:
DynamicDataSourceHolder.setDataSource("XXXX"); //值為配置檔案裡面資料源設定的加載key

最後測試下,寫一個接口簡單測試下:
@Autowired
MessageboardService messageboardServiceImpl;
@Autowired
JdbcConfigService jdbcConfigServiceImpl;
@RequestMapping(value = "/testDbSource", produces = "application/json; charset=utf-8")
public void testDbSource() {
DynamicDataSourceHolder.setDataSource("firstSource"); //切換到資料源1
Messageboard message = messageboardServiceImpl.selectByPrimaryKey(5);
System.out.println(message.toString());
DynamicDataSourceHolder.setDataSource("secondSource"); //切換到資料源2
JdbcConfig jdbcConfig = jdbcConfigServiceImpl.selectByGameId("1234");
System.out.println(jdbcConfig.toString());
DynamicDataSourceHolder.setDataSource("firstSource"); //切換到資料源1
Messageboard messageExtra = messageboardServiceImpl.selectByPrimaryKey(4);
System.out.println(messageExtra.toString());
}
運作這個接口,我們會切換到第一個資料源進行操作,然後切換到第二個資料源進行操作,再切換到第一個資料源進行操作: