SSM 最简单的实现操作 多数据源&动态切换

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: SSM 最简单的实现操作 多数据源&动态切换

在项目开发里面,多数据源是最普遍不过的,一个项目使用多个数据库是非常正常的,那么这篇就是基于SSM框架去轻松实现使用多数据源的实战场景。


基于SSM框架(还不了解SSM的的可以参考:https://blog.csdn.net/qq_35387940/article/details/97911104


开始,


首先准备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

image.png


最后测试下,写一个接口简单测试下:


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


运行这个接口,我们会切换到第一个数据源进行操作,然后切换到第二个数据源进行操作,再切换到第一个数据源进行操作:


image.png


看下控制台输出(可以看到,切换自如):


image.png


好,多数据源的简单使用就到此吧。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
9月前
java202304java学习笔记第六十六天-ssm-动态sql-一对一的配置实现1
java202304java学习笔记第六十六天-ssm-动态sql-一对一的配置实现1
40 0
|
9月前
java202304java学习笔记第六十七天-ssm-动态sql-多对多注解开发之1
java202304java学习笔记第六十七天-ssm-动态sql-多对多注解开发之1
37 0
|
9月前
java202304java学习笔记第六十七天-ssm-动态sql-多对多配置实现2
java202304java学习笔记第六十七天-ssm-动态sql-多对多配置实现2
43 1
|
9月前
java202304java学习笔记第六十七天-ssm-动态sql-知识小结
java202304java学习笔记第六十七天-ssm-动态sql-知识小结
40 0
|
9月前
java202304java学习笔记第六十七天-ssm-动态sql-一对多配置2
java202304java学习笔记第六十七天-ssm-动态sql-一对多配置2
40 0
|
9月前
java202304java学习笔记第六十七天-ssm-动态sql-一对多配置
java202304java学习笔记第六十七天-ssm-动态sql-一对多配置
47 0
|
9月前
java202304java学习笔记第六十七天-ssm-动态sql-一对一的配置实现2
java202304java学习笔记第六十七天-ssm-动态sql-一对一的配置实现2
45 0
java202304java学习笔记第六十七天-ssm-动态sql-一对一的配置实现2
|
9月前
java202304java学习笔记第六十六天-ssm-动态sql-一对一的配置实现2
java202304java学习笔记第六十六天-ssm-动态sql-一对一的配置实现2
46 0
|
9月前
java202304java学习笔记第六十七天-ssm-动态sql-多对多注解开发之2
java202304java学习笔记第六十七天-ssm-动态sql-多对多注解开发之2
39 0
java202304java学习笔记第六十七天-ssm-动态sql-多对多注解开发之2
|
9月前
java202304java学习笔记第六十七天-ssm-动态sql-一对多得注解开发2
java202304java学习笔记第六十七天-ssm-动态sql-一对多得注解开发2
40 0