SSM项目中扩展多数据源mysql

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 一个ssm项目中需要扩展多个数据源,原来只有一个mysql,现在需要再扩展一个mysql,现将需要改动的地方做一个记录。

一个ssm项目中需要扩展多个数据源,原来只有一个mysql,现在需要再扩展一个mysql,现将需要改动的地方做一个记录。

db.properties修改

首先,需要在数据源配置文件中增加新数据源配置。因为都是mysql,除了需要改动的,其他配置都是用了一样的参数,如果需要更改,可以自行增加配置参数。

# 数据源1
jdbc.user=root
jdbc.password=root
jdbc.jdbcUrl=jdbc\:mysql\://localhost\:3306/db1?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false

# 数据源2
jdbc2.jdbcUrl=jdbc:mysql://localhost:3306/db1?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
jdbc2.user=root
jdbc2.password=root

# 公用配置
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.initPoolSize=5
jdbc.maxPoolSize=1024

spring.xml修改

spring.xml中需要新增数据源配置,以及多源数据库如何选择的配置。

    <!-- 导入资源文件 -->
    <context:property-placeholder location="classpath:db.properties"/>

    <!-- db1数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="driverClass" value="${jdbc.driverClass}"></property>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
        <property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
        <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
    </bean>
    <!--    db2数据库-->
    <bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${jdbc2.user}"></property>
        <property name="password" value="${jdbc2.password}"></property>
        <property name="driverClass" value="${jdbc.driverClass}"></property>
        <property name="jdbcUrl" value="${jdbc2.jdbcUrl}"></property>
        <property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
        <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
    </bean>
      
    <!-- 动态选择数据源,指向com.demo.test.dataSource.DynamicDataSource,后文会贴出代码 -->
    <bean id="dynamicDataSource" class="com.demo.test.dataSource.DynamicDataSource">
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <entry key="defaultDB" value-ref="dataSource"/>
                <entry key="DataDB" value-ref="dataSource2"/>
            </map>
        </property>
        <!--默认数据源-->
        <property name="defaultTargetDataSource" ref="dataSource2"/>
    </bean>
      
    <!-- 配置 SessionFactory -->
    <bean id="sessionFactory"
          class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <!-- 更改指向 dynamicDataSource -->
        <property name="dataSource" ref="dynamicDataSource"></property>
        <property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
    </bean>

增加数据源切换类

数据源枚举类

public enum DataSourceEnum {
    DS1("defaultDB"), DS2("DataDB");
    private String key;

    DataSourceEnum(String key) {
        this.key = key;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }
}

线程持有数据源标识类

用于标记线程使用哪个数据源标识

public class DataSourceHolder {
    private static final ThreadLocal<String> dataSources = new ThreadLocal<String>();

    public static void setDataSources(String dataSource) {
        dataSources.set(dataSource);
    }

    public static String getDataSources() {
        return dataSources.get();
    }
}

配置动态数据源类

AbstractRoutingDataSource 类:可以根据用户定义的规则选择当前的数据源,多源数据库需要使用该类实现多源数据库选择。

在每次数据库查询操作前执行,determineCurrentLookupKey() 决定使用哪个数据源。

实现的具体逻辑:继承 AbstractRoutingDataSource 类并重写 determineCurrentLookupKey 方法。把配置的多个数据源会放在AbstractRoutingDataSource的 targetDataSources和defaultTargetDataSource中,然后通过afterPropertiesSet()方法将数据源分别进行复制到resolvedDataSources和resolvedDefaultDataSource中。调用AbstractRoutingDataSource的getConnection()的方法的时候,先调用determineTargetDataSource()方法返回DataSource在进行getConnection()。

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceHolder.getDataSources();
    }
}

切换数据源代码

配置完上诉代码,到此可以在查询数据源时增加一个选择数据源语句实现选择数据源。例如:

    public User test01(String username) {
        DataSourceHolder.setDataSources(DataSourceEnum.DS1.getKey());
        return userDao.findUserByName(username);
    }

    public User test02(String username) {
        DataSourceHolder.setDataSources(DataSourceEnum.DS2.getKey());
        return userDao.findUserByName(username);
    }

自动切换数据源

手动切换数据源需要每个方法都需要进行修改,太过于麻烦。

这里可以利用aop,实现根据包名自动切换数据源。

切面类

db1数据源都在db1包名下,db2数据源都在db2数据源下。如果你的项目文件结构不适用,可以根据能区分开数据源的策略进行自动切换,这个策略需要你自己去想了👻。

public class DataSourceExchange {
    public void before(JoinPoint point) {
        //获取目标对象的类类型
        Class<?> aClass = point.getTarget().getClass();
        String c = aClass.getName();
        String[] ss = c.split("\\.");
        //获取包名,进行数据源选择。这里根据需求进行修改。
        String packageName = ss[3];
        if ("db2".equals(packageName)) {
            DataSourceHolder.setDataSources(DataSourceEnum.DS2.getKey());
//            System.out.println("数据源:" + DataSourceEnum.DS2.getKey());
        } else {
            DataSourceHolder.setDataSources(DataSourceEnum.DS1.getKey());
//            System.out.println("数据源:" + DataSourceEnum.DS1.getKey());
        }
    }

    /**
     * 执行后将数据源置为空
     */
    public void after() {
        DataSourceHolder.setDataSources(null);
    }
}

在配置中设置切面

bean id为bean的名称,class指向类的位置;aop的execution表示筛选的类,method表示对类使用的方法。

    <!-- DataSourceExchange 注入bean -->
    <bean id="dataSourceExchange" class="com.demo.test.dataSource.DataSourceExchange"/>
    <!-- 配置aop切面 -->
    <aop:config>
        <aop:aspect ref="dataSourceExchange">
        <!-- 限定在哪些包下执行 -->
            <aop:pointcut id="dataSourcePointcut" expression="execution(* com.demo.test..service.impl.*ServiceImpl.*(..))"/>
            <aop:before pointcut-ref="dataSourcePointcut" method="before"/>
            <aop:after pointcut-ref="dataSourcePointcut" method="after"/>
        </aop:aspect>
    </aop:config>

execution语法说明:

比如:* com.demo.test..service.impl.*ServiceImpl.*(..))

第一个 * 表示任意返回值

.. 表示 test 包和它的所有子包

*ServiceImpl 表示任何前缀的ServiceImpl类

最后的*表示,命中类的所有方法

总结

修改配置到这里就已经完成了ssm配置多数据源修改了,如果还出现了报错,请查看错误日志,很可能是配置的参数中指向错误,细心点检查下。

最后的运行结果:image-20220926091943330

测试完,记得把输出注释掉哦

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
8天前
|
关系型数据库 MySQL 数据挖掘
轻松入门MySQL:深入理解MySQL聚合函数,实战进销存项目中的应用与技巧(8)
轻松入门MySQL:深入理解MySQL聚合函数,实战进销存项目中的应用与技巧(8)
|
6天前
|
前端开发 JavaScript Java
Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)五(前端页面
Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)五(前端页面
Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)五(前端页面
|
8天前
|
JavaScript Java 项目管理
基于SSM大创项目申报管理系统的设计与实现
基于SSM大创项目申报管理系统的设计与实现
23 2
|
8天前
|
关系型数据库 MySQL Java
启动项目出现com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException异常解决方法
启动项目出现com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException异常解决方法
|
8天前
|
应用服务中间件
【SSM】如何在IDEA配置tomcat启动项目
【SSM】如何在IDEA配置tomcat启动项目
26 1
|
8天前
|
数据库
【SSM】如何修改配置文件重启项目
【SSM】如何修改配置文件重启项目
11 1
|
8天前
|
监控 数据可视化 安全
智慧工地SaaS可视化平台源码,PC端+APP端,支持二开,项目使用,微服务+Java++vue+mysql
环境实时数据、动态监测报警,实时监控施工环境状态,有针对性地预防施工过程中的环境污染问题,打造文明生态施工,创造绿色的生态环境。
22 0
智慧工地SaaS可视化平台源码,PC端+APP端,支持二开,项目使用,微服务+Java++vue+mysql
|
8天前
|
关系型数据库 MySQL Docker
Docker从容器中项目如何访问到宿主机MYSQL
Docker从容器中项目如何访问到宿主机MYSQL
200 0
|
8天前
|
JavaScript Java 关系型数据库
实例!使用Idea创建SSM框架的Maven项目
实例!使用Idea创建SSM框架的Maven项目
49 0
|
8天前
|
Java 关系型数据库 MySQL
【项目】手把手带你用 SpringBoot、Uniapp、MySql 开发一个简单的活动报名项目
【项目】手把手带你用 SpringBoot、Uniapp、MySql 开发一个简单的活动报名项目
206 1