Spring Boot 项目中使用 Dynamic Datasource 实现多数据源管理

一 、概述

在现代企业级应用开发中,多数据源管理是一个常见的需求。无论是为了数据隔离、读写分离还是业务分库,都需要对多个数据源进行统一管理。本文将详细介绍如何在 Spring Boot 项目中使用 com.baomidou.dynamic.datasource 库来实现多数据源管理。

二、项目准备

1. 添加依赖

首先,在 l pom.xmll 文件中添加多数据源管理所需的依赖:

xml 复制代码
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.5.2</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2. 配置多数据源

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

yaml 复制代码
spring:
  datasource:
    dynamic:
      primary: master # 设置默认数据源
      strict: false
      datasource:
        master:
          url: jdbc:mysql://localhost:3306/master_db?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
          username: root
          password: password
          driver-class-name: com.mysql.cj.jdbc.Driver
        slave1:
          url: jdbc:mysql://localhost:3306/slave1_db?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
          username: root
          password: password
          driver-class-name: com.mysql.cj.jdbc.Driver
        slave2:
          url: jdbc:mysql://localhost:3306/slave2_db?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
          username: root
          password: password
          driver-class-name: com.mysql.cj.jdbc.Driver

三、核心注解介绍

1. DS 注解

根据你提供的代码,DS 注解是动态数据源的核心注解:

java 复制代码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DS {
    String value();
}
  • @Target({ElementType.TYPE, ElementType.METHOD}):表示该注解可以作用于类和方法
  • @Retention(RetentionPolicy.RUNTIME):表示该注解在运行时有效
  • String value():指定数据源的名称

四、实现多数据源管理

1. 创建实体类

java 复制代码
// User.java
package com.example.entity;

public class User {
    private Long id;
    private String name;
    private String email;
    
    // 构造函数
    public User() {}
    
    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }
    
    // Getter 和 Setter
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
}

2. 创建数据访问层

java 复制代码
// UserMapper.java
package com.example.mapper;

import com.example.entity.User;
import org.apache.ibatis.annotations.*;
import java.util.List;

@Mapper
public interface UserMapper {
    
    @Select("SELECT * FROM users")
    List<User> findAll();
    
    @Insert("INSERT INTO users(name, email) VALUES(#{name}, #{email})")
    int insert(User user);
    
    @Update("UPDATE users SET name=#{name}, email=#{email} WHERE id=#{id}")
    int update(User user);
    
    @Delete("DELETE FROM users WHERE id=#{id}")
    int delete(Long id);
}

3. 创建服务层 - 使用不同数据源

java 复制代码
// UserService.java
package com.example.service;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.example.entity.User;
import com.example.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    // 使用主数据源
    @DS("master")
    public List<User> getMasterUsers() {
        System.out.println("从主数据源查询用户");
        return userMapper.findAll();
    }
    
    // 使用从数据源1
    @DS("slave1")
    public List<User> getSlave1Users() {
        System.out.println("从从数据源1查询用户");
        return userMapper.findAll();
    }
    
    // 使用从数据源2
    @DS("slave2")
    public List<User> getSlave2Users() {
        System.out.println("从从数据源2查询用户");
        return userMapper.findAll();
    }
    
    // 在类级别指定数据源
    @DS("master")
    public void addUserToMaster(User user) {
        userMapper.insert(user);
    }
    
    // 方法级别覆盖类级别的数据源设置
    @DS("slave1")
    public void addUserToSlave1(User user) {
        userMapper.insert(user);
    }
}

4. 创建控制器

java 复制代码
// UserController.java
package com.example.controller;

import com.example.entity.User;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping("/master")
    public List<User> getMasterUsers() {
        return userService.getMasterUsers();
    }
    
    @GetMapping("/slave1")
    public List<User> getSlave1Users() {
        return userService.getSlave1Users();
    }
    
    @GetMapping("/slave2")
    public List<User> getSlave2Users() {
        return userService.getSlave2Users();
    }
    
    @PostMapping("/master")
    public String addMasterUser(@RequestBody User user) {
        userService.addUserToMaster(user);
        return "用户已添加到主数据源";
    }
    
    @PostMapping("/slave1")
    public String addSlave1User(@RequestBody User user) {
        userService.addUserToSlave1(user);
        return "用户已添加到从数据源1";
    }
}

五、高级用法

1. 在Service类级别使用DS注解

java 复制代码
@Service
@DS("master")  // 整个类都使用master数据源
public class MasterUserService {
    
    @Autowired
    private UserMapper userMapper;
    
    // 这个方法会使用master数据源
    public List<User> getAllUsers() {
        return userMapper.findAll();
    }
    
    // 这个方法会覆盖类级别的设置,使用slave1数据源
    @DS("slave1")  
    public void saveToSlave1(User user) {
        userMapper.insert(user);
    }
}

2. 使用SpEL表达式

java 复制代码
@Service
public class DynamicUserService {
    
    @Autowired
    private UserMapper userMapper;
    
    // 使用SpEL表达式动态选择数据源
    @DS("#user.type")  // 根据user对象的type属性选择数据源
    public void saveUserByType(User user) {
        userMapper.insert(user);
    }
    
    // 根据方法参数动态选择数据源
    @DS("#dsName")
    public List<User> getUsersByDataSource(String dsName) {
        return userMapper.findAll();
    }
}

3. 在Mapper类级别使用DS注解

java 复制代码
// 整个类都使用master数据源
@Mapper
@DS("master")
public interface UserMapper extends BaseMapper<User> {

}

六、数据库表结构

为演示效果,创建三个数据库的用户表:

sql 复制代码
-- master_db
CREATE TABLE users (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50),
    email VARCHAR(100)
);

-- slave1_db
CREATE TABLE users (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50),
    email VARCHAR(100)
);

-- slave2_db
CREATE TABLE users (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50),
    email VARCHAR(100)
);

七、测试验证

启动应用后,可以通过以下API进行测试:

  • GET /users/master - 从主数据源获取用户
  • GET /users/slave1 - 从从数据源1获取用户
  • GET /users/slave2 - 从从数据源2获取用户
  • POST /users/master - 向主数据源添加用户
  • POST /users/slave1 - 向从数据源1添加用户

八、总结

通过使用 com.baomidou.dynamic.datasource 库,我们可以非常方便地在 Spring Boot 项目中实现多数据源管理。主要优点包括:

  • 简单易用 :通过 @DS 注解即可切换数据源
  • 灵活配置:支持方法级和类级注解
  • 动态切换:支持基于表达式的动态数据源选择
  • 性能良好:底层基于 Spring 的事务管理,性能优秀

这种方案特别适合需要读写分离、多租户、分库分表等场景,是企业级应用开发中的重要技术方案。

相关推荐
晴虹2 小时前
lecen:一个更好的开源可视化系统搭建项目--页面设计器(表单设计器)--全低代码|所见即所得|利用可视化设计器构建你的应用系统-做一个懂你的人
前端·后端·低代码
苏三的开发日记2 小时前
Hive的安装与配置
后端
小楼v2 小时前
一篇学会在IDEA中的Git常用操作及冲突的解决方法
git·后端
EMQX2 小时前
利用 EMQX 消息队列解决关键物联网消息传递挑战
人工智能·后端·物联网·mqtt·emqx
red润3 小时前
Python环境变量自动配置:实现生产与开发环境无缝切换
后端·python
幽络源小助理3 小时前
下载安装AndroidStudio配置Gradle运行第一个kotlin程序
android·开发语言·kotlin
给我推荐个名字3 小时前
pageoffice提取Excel表格区域数据
后端
幽络源小助理3 小时前
SpringBoot+Vue攀枝花水果在线销售系统源码 | Java项目免费下载 – 幽络源
java·vue.js·spring boot
inBuilder低代码平台3 小时前
浅谈安卓Webview从初级到高级应用
android·java·webview