一 、概述
在现代企业级应用开发中,多数据源管理是一个常见的需求。无论是为了数据隔离、读写分离还是业务分库,都需要对多个数据源进行统一管理。本文将详细介绍如何在 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 的事务管理,性能优秀
这种方案特别适合需要读写分离、多租户、分库分表等场景,是企业级应用开发中的重要技术方案。