天天看點

SSM 最簡單的實作操作 多資料源&動态切換

在項目開發裡面,多資料源是最普遍不過的,一個項目使用多個資料庫是非常正常的,那麼這篇就是基于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      
SSM 最簡單的實作操作 多資料源&amp;動态切換

最後測試下,寫一個接口簡單測試下:

@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());
    }      

運作這個接口,我們會切換到第一個資料源進行操作,然後切換到第二個資料源進行操作,再切換到第一個資料源進行操作:

SSM 最簡單的實作操作 多資料源&amp;動态切換

繼續閱讀