开发者

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

目录
  • 1、简述
  • 2、什么是 Dynamic-DataSource?
  • 3、集成 Dynamic-DataSource
    • 3.1 Maven引用
    • 3.2 配置多数据源
    • 3.3 编写动态数据源切换逻辑
  • 4、总结

    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&serjavascriptverTimezone=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.jsentry.SysUserEntity;
    import com.lm.shop.shopeureka.mapper.SysUserMapper;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    @Service
    public class UserService extends ServicandroideImpl<SysUserMapper, SysUserEntity> {
    
        @Reshttp://www.devze.comource
        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;
    
        /**
         * 手机号
         */
        @javascriptTableField("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动态数据源切换的资料请关注编程客栈(www.devze.com)其它相关文章!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜