Java实现动态数据源切换的实践指南

 更新时间:2025年03月06日 10:25:02   作者:拾荒的小海螺  
在 Java 开发中,许多场景需要访问多个数据库,例如多租户系统或读写分离架构,为了灵活高效地管理这些场景,动态数据源切换技术应运而生,所以本文给大家介绍了Java实现动态数据源切换的实践指南,需要的朋友可以参考下

1、简述

在 Java 开发中,许多场景需要访问多个数据库,例如多租户系统或读写分离架构。为了灵活高效地管理这些场景,动态数据源切换(Dynamic-DataSource) 技术应运而生。

本文介绍如何在 Spring Boot 项目中集成 Dynamic-DataSource 并实现动态切换功能,最后通过示例演示实际应用。

2、什么是 Dynamic-DataSource?

Dynamic-DataSource 是一种可以根据业务需求动态切换数据源的技术。常见的使用场景包括:

  • 读写分离:读请求路由到只读数据源,写请求路由到主数据源。
  • 多租户系统:根据租户 ID 动态选择数据库。
  • 分库分表:根据分片键路由到对应的数据源。

通过动态数据源切换,可以避免手动管理多个 DataSource,提升开发效率。Dynamic-DataSource 基于 Spring 的 AbstractRoutingDataSource 实现。核心思想是:

  • 定义多个数据源(如主库和从库)。
  • 使用线程上下文(ThreadLocal)保存当前使用的数据源标识。
  • 根据上下文动态选择数据源。

3、集成 Dynamic-DataSource

dynamic-datasource-spring-boot-starter 是一个基于springboot的快速集成多数据源的启动器。

  • 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。
  • 支持数据库敏感配置信息 加密(可自定义) ENC()。
  • 支持每个数据库独立初始化表结构schema和数据库database。
  • 支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。
  • 提供并简化对Druid,HikariCp,BeeCp,Dbcp2的快速集成。

提供对Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi等组件的集成方案。

3.1 Maven引用

在使用 Dynamic-DataSource之前,需要添加其依赖。以下是 Dynamic-DataSource的 Maven 依赖:

<!-- mybatis-plus -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.3.1</version>
</dependency>
<!-- mysql -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.19</version>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>4.3.0</version>
</dependency>

3.2 配置多数据源

在 application.yml 文件中配置多个数据源:

server:
  port: 9001

spring:
  datasource:
    dynamic:
      primary: master
      strict: false
      datasource:
        master:
          url: jdbc:mysql://192.168.25.181:3306/shop_admin?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
          username: root
          password: 123456
          driver-class-name: com.mysql.cj.jdbc.Driver
        slave_1:
          url: jdbc:mysql://192.168.25.181:3306/slave_db?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
          username: root
          password: 123456
          driver-class-name: com.mysql.cj.jdbc.Driver

3.3 编写动态数据源切换逻辑

Dynamic-DataSource Starter 提供了注解和 AOP 的支持,可以简化数据源切换逻辑。在需要动态切换数据源的地方添加 @DS 注解:

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lm.shop.shopeureka.entry.SysUserEntity;
import com.lm.shop.shopeureka.mapper.SysUserMapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class UserService extends ServiceImpl<SysUserMapper, SysUserEntity> {

    @Resource
    private SysUserMapper sysUserMapper;

    @DS("master")
    public void insertUser(SysUserEntity user) {
        sysUserMapper.insert(user);
    }

    @DS("slave_1")
    public SysUserEntity getUserById(Long id){
        return sysUserMapper.selectById(id);
    }
}

SysUserMapper:

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lm.shop.shopeureka.entry.SysUserEntity;

public interface SysUserMapper extends BaseMapper<SysUserEntity> {
}

SysUserEntity:

package com.lm.shop.shopeureka.entry;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

@Data
@TableName("sys_user")
public class SysUserEntity  implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 用户ID
     */
    @TableId(value = "user_id")
    private Long userId;

    /**
     * 用户名
     */
    @TableField("username")
    private String username;

    /**
     * 密码
     */
    @TableField("password")
    private String password;

    /**
     * 盐
     */
    @TableField("salt")
    private String salt;

    /**
     * 邮箱
     */
    @TableField("email")
    private String email;

    /**
     * 手机号
     */
    @TableField("mobile")
    private String mobile;

    /**
     * 状态  0:禁用   1:正常
     */
    @TableField("status")
    private Integer status;

    /**
     * 创建者ID
     */
    @TableField("create_user_id")
    private Long createUserId;

    /**
     * 创建时间
     */
    @TableField("create_time")
    private Date createTime;
}

在Controller控制层添加测试用例:

import com.lm.shop.shopeureka.entry.SysUserEntity;
import com.lm.shop.shopeureka.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/getUserById")
    public SysUserEntity getUserById(@RequestParam Long id) {
        return userService.getUserById(id);
    }

    @GetMapping("/insert")
    public SysUserEntity insert(@RequestParam Long id) {
        SysUserEntity sysUserEntity = new SysUserEntity();
        sysUserEntity.setEmail("admin@admin.com");
        sysUserEntity.setPassword("123456");
        sysUserEntity.setUsername("adminMaster");
        sysUserEntity.setCreateTime(new Date());
         userService.insertUser(sysUserEntity);
         return sysUserEntity;
    }
}

在启动类中添加mapper映射路径:

@SpringBootApplication
@MapperScan("com.lm.shop.shopeureka.mapper")
public class ShopEurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(ShopEurekaApplication.class, args);
    }
}

4、总结

Dynamic-DataSource 提供了一种高效、简洁的多数据源管理方式,非常适合多租户系统、读写分离等复杂场景。本文通过配置和实际案例展示了如何集成和使用 Dynamic-DataSource,帮助开发者快速实现动态数据源切换功能。

通过动态数据源技术,可以显著提高系统的灵活性和扩展性。如果你的项目中涉及多个数据库的管理,Dynamic-DataSource 将是一个强大的工具。

以上就是Java实现动态数据源切换的实践指南的详细内容,更多关于Java动态数据源切换的资料请关注脚本之家其它相关文章!

相关文章

  • javaweb实现简易邮件发送

    javaweb实现简易邮件发送

    这篇文章主要为大家详细介绍了javaweb实现简易邮件发送,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • scala 读取txt文件的方法示例

    scala 读取txt文件的方法示例

    这篇文章主要介绍了scala 读取txt文件的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-06-06
  • Java中的String不可变性实现

    Java中的String不可变性实现

    在Java编程中,String类的不可变性是一个被广泛讨论和利用的特性,本文主要介绍了Java中的String不可变性实现,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • Spring整合Quartz Job以及Spring Task的实现方法

    Spring整合Quartz Job以及Spring Task的实现方法

    下面小编就为大家分享一篇Spring整合Quartz Job以及Spring Task的实现方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-12-12
  • Maven本地存在jar包IDEA依旧爆红的完美解决方法

    Maven本地存在jar包IDEA依旧爆红的完美解决方法

    这篇文章主要介绍了Maven本地存在jar包IDEA依旧爆红的完美解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-06-06
  • JVM内存增强之逃逸分析

    JVM内存增强之逃逸分析

    逃逸分析一种数据分析算法,基于此算法可以有效减少Java对象在堆内存中的分配。本文将详细讲讲逃逸分析的原理与实现,需要的可以参考一下
    2022-09-09
  • 基于Java手写一个好用的FTP操作工具类

    基于Java手写一个好用的FTP操作工具类

    网上百度了很多FTP的java 工具类,发现文章代码都比较久远,且代码臃肿,即使搜到了代码写的还可以的,封装的常用操作方法不全面。所以本文将手写一个好用的Java FTP操作工具类,需要的可以参考一下
    2022-04-04
  • Java并发框架:Executor API详解

    Java并发框架:Executor API详解

    这篇文章主要介绍了Java并发框架:Executor API详解,随着当今处理器中可用的核心数量的增加, 随着对实现更高吞吐量的需求的不断增长,多线程 API 变得非常流行。 Java 提供了自己的多线程框架,称为 Executor 框架,需要的朋友可以参考下
    2019-07-07
  • java简单操作word实例

    java简单操作word实例

    这篇文章主要为大家详细介绍了java简单操作word实例,感兴趣的朋友可以参考一下
    2016-03-03
  • java身份证验证代码实现

    java身份证验证代码实现

    java身份证验证代码实现,需要的朋友可以参考一下
    2013-02-02

最新评论