MySql之SpringBoot集成动态数据源

本文介绍了在SpringBoot中如何配置和使用动态数据源,以实现在多个数据库间切换执行SQL。通过示例展示了主从数据源的配置,自定义动态数据源类,以及如何在代码中切换数据源。同时指出了这种方式的缺点,如手动切换可能导致错误、无法进行负载均衡和故障转移,并提示需要自定义管理代码来解决这些问题。
摘要由CSDN通过智能技术生成

概述

某些场景下,业务需要使用到多个数据库,这种场景下需要使用动态数据源的方式来执行相关sql。

多数据属性配置

#tomcat port
server.port=8080

# 主数据源配置
master.datasource.driver-class-name=com.mysql.jdbc.Driver
master.datasource.url=jdbc:mysql://192.168.195.129:3306/practice?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowPublicKeyRetrieval=true
master.datasource.username=root
master.datasource.password=123456
# 从数据源配置
slave.datasource.driver-class-name=com.mysql.jdbc.Driver
slave.datasource.url=jdbc:mysql://192.168.195.129:3307/practice?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowPublicKeyRetrieval=true
slave.datasource.username=root
slave.datasource.password=123456

#datasource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.195.129:3306/practice?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=123456

线程设置使用哪个数据库

public class MyThreadLocal {
    public static final ThreadLocal<String> local = new ThreadLocal<>();

    public static String getDataSource() {
        return local.get();
    }

    public static void setDataSource(String dataSource) {
        local.set(dataSource);
    }
}

自定义动态数据源类

package com.practice.tkmybatis.config;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * 自定义动态数据源类用于在程序运行中切换数据源,并集成动态数据源的抽象父类
 */
public class MyDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return MyThreadLocal.getDataSource();
    }
}

动态数据源配置

package com.practice.tkmybatis.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
* 动态多数据源,这种方案我们需要自定义一个动态数据源的类,可以在程序运行过程中动态切换数据源。
* 缺点:
*   1、有很多的重复代码,例如springBoot中配置多个数据源的配置Bean;
*   2、切换主从进行读写操作时需要程序任务手动设置ThreadLocal中数据,这样就可能向从数据库中写数据;
*   3、如果有很多个从节点,那么我们没有办法进行负载均衡;
*   4、如果某个节点崩溃我们不能切换到另外一台节点中,不能故障转移;
* 注意:
*    如果需要解决上面的问题,我们需要自己写一套管理代码来动态的切换数据源进行读写分离,故障转移等。
**/
@Configuration
@MapperScan(basePackages = {"com.practice.tkmybatis.mapper"}, sqlSessionFactoryRef = "sqlSessionFactoryBean")
public class DataSourceConfig {

    /**
     * 主库属性
     */
    @Value("${master.datasource.driver-class-name}")
    private String masterDriverClassName;

    @Value("${master.datasource.url}")
    private String masterUrl;

    @Value("${master.datasource.username}")
    private String masterUserName;

    @Value("${master.datasource.password}")
    private String masterPassword;

    /**
     * 从库属性
     */
    @Value("${slave.datasource.driver-class-name}")
    private String slaveDriverClassName;

    @Value("${slave.datasource.url}")
    private String slaveUrl;

    @Value("${slave.datasource.username}")
    private String slaveUserName;

    @Value("${slave.datasource.password}")
    private String slavePassword;

    /**
     * 主库配置
     *
     * @return
     */
    @Bean
    public DruidDataSource masterDruidDataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(masterDriverClassName);
        druidDataSource.setUrl(masterUrl);
        druidDataSource.setUsername(masterUserName);
        druidDataSource.setPassword(masterPassword);
        return druidDataSource;
    }

    /**
     * 从库配置
     *
     * @return
     */
    @Bean
    public DruidDataSource slaveDruidDataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(slaveDriverClassName);
        druidDataSource.setUrl(slaveUrl);
        druidDataSource.setUsername(slaveUserName);
        druidDataSource.setPassword(slavePassword);
        return druidDataSource;
    }

    /**
     * 配置动态数据类
     *
     * @param masterDruidDataSource 主数据源
     * @param slaveDruidDataSource  从数据源
     * @return 动态数据源
     */
    public MyDataSource myDataSource(DruidDataSource masterDruidDataSource, DruidDataSource slaveDruidDataSource) {
        MyDataSource myDataSource = new MyDataSource();
        myDataSource.setDefaultTargetDataSource(masterDruidDataSource);
        Map<Object, Object> dataSourceMap = new HashMap<>();
        dataSourceMap.put("master", masterDruidDataSource);
        dataSourceMap.put("slave", slaveDruidDataSource);
        myDataSource.setTargetDataSources(dataSourceMap);
        return myDataSource;
    }

    public SqlSessionFactoryBean sqlSessionFactoryBean(MyDataSource myDataSource) {
        final SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(myDataSource);
        return sqlSessionFactoryBean;
    }

    // 测试方法
    public static void main(String[] args) {
        MyThreadLocal.setDataSource("master");
        // 执行master库的逻辑
        MyThreadLocal.setDataSource("slave");
        // 执行slave库的逻辑
    }
}

参考

MySQL集群-SpringBoot集成多数据源
SpringBoot集成AbstractRoutingDataSource实现动态切换多数据源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

融极

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值