添加依赖
首先,在你的 pom.xml
中添加 dynamic-datasource-spring-boot-starter
依赖。建议使用较新的版本,例如:
<dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.5.0</version> <!-- 请注意检查最新版本 --> </dependency> <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope> </dependency>
如果你的项目已经包含了 MyBatis-Plus 或 Druid 等相关依赖,通常可以共存。
⚙️ 配置文件设置
在 application.yml
(或 application.properties
) 中配置你的多个数据源。以下是一个配置两个数据源(一个主数据源 master
,一个从数据源 slave_1
)的示例:
spring:datasource:dynamic:primary: master # 设置默认的数据源名称,默认就是'master'strict: false # 是否严格匹配数据源。true 时未匹配到指定数据源则抛异常;false 则使用默认数据源。默认为 false。datasource:master: # 数据源名称,你可以自定义url: jdbc:mysql://localhost:3306/master_db?useSSL=false&serverTimezone=UTC&characterEncoding=utf8username: your_master_usernamepassword: your_master_passworddriver-class-name: com.mysql.cj.jdbc.Driver # 高版本支持 SPI 时可省略slave_1: # 另一个数据源的名称url: jdbc:mysql://localhost:3306/slave_db?useSSL=false&serverTimezone=UTC&characterEncoding=utf8username: your_slave_usernamepassword: your_slave_passworddriver-class-name: com.mysql.cj.jdbc.Driver # 如果需要配置连接池参数(如使用 Druid 或 HikariCP 的特定设置),可以像下面这样,注意缩进层级:master:# ... 同上 master 数据源的基本连接信息 ...druid: # 假设使用 Druid 连接池initial-size: 5max-active: 20min-idle: 5max-wait: 60000slave_1:# ... 同上 slave_1 数据源的基本连接信息 ...druid:initial-size: 3max-active: 10min-idle: 2max-wait: 60000
关键配置项说明:
-
spring.datasource.dynamic.primary
: 指定默认使用的数据源名称。 -
spring.datasource.dynamic.strict
: 设置是否严格匹配数据源。 -
spring.datasource.dynamic.datasource
: 其下配置各个具体的数据源,名称(如master
,slave_1
)可以自定义,后续会通过@DS
注解引用这些名称。
🔧 启动类配置(可选,主要针对 Druid)
如果你使用 Druid 连接池,为了避免其自动配置与 dynamic-datasource 的配置冲突,通常需要在启动类上排除 Druid 的自动配置类:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; // 如果使用 Druid 才需要 exclude import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class) // 排除 Druid 自动配置 public class YourApplication {public static void main(String[] args) {SpringApplication.run(YourApplication.class, args);} }
排除的原因:Druid 的自动配置类 (DruidDataSourceAutoConfigure
) 可能会尝试从 spring.datasource
路径下读取配置,而 dynamic-datasource-spring-boot-starter
的数据源配置路径是 spring.datasource.dynamic.datasource
,路径不同可能导致冲突或配置失效。如果你使用的是 Spring Boot 默认的 HikariCP 或其他连接池,通常不需要进行此项排除。
🏷️ 使用 @DS 注解切换数据源
配置好多数据源后,就可以在代码中使用 @com.baomidou.dynamic.datasource.annotation.DS
注解来切换数据源了。
@DS
注解可以标注在 Service 实现类 或 Service 实现类的方法 上。强烈建议在 Service 层进行数据源切换,而不是在 Mapper 层。
注解规则与示例
@DS
注解的切换遵循一定的规则,下面的表格总结了常见的用法:
注解位置 | 示例代码 | 作用说明 |
---|---|---|
Service 类上 | @DS("slave_1") public class UserServiceImpl |
该 Service 所有方法默认使用 slave_1 数据源。 |
Service 方法上 | @DS("master") public void updateUser(User user) |
此方法使用 master 数据源。 |
无注解 | public List<User> selectUsers() |
使用 primary 指定的默认数据源(例如 master )。 |
方法注解覆盖类注解 | 类上 @DS("slave") , 方法上 @DS("master") |
方法上的注解优先级高于类上的注解,该方法使用 master 数据源。 |
示例代码:
-
在 Service 实现类的方法上使用
@DS
注解
import com.baomidou.dynamic.datasource.annotation.DS; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import java.util.List; import java.util.Map;@Service public class UserServiceImpl implements UserService {@Autowiredprivate JdbcTemplate jdbcTemplate; // 注入 JdbcTemplate// 该方法使用默认数据源 (master) @Overridepublic List<User> getMasterUser(Long id) {String sql = "SELECT * FROM user WHERE id = ?";return jdbcTemplate.queryForList(sql, id);}// 该方法使用 slave_1 数据源 @Override@DS("slave_1")public List<Map<String, Object>> getSlaveUser(Long id) {String sql = "SELECT * FROM user WHERE id = ?";return jdbcTemplate.queryForList(sql, id);}// 写操作通常指定到主库 @Override@DS("master")public int updateUser(User user) {String sql = "UPDATE user SET name = ? WHERE id = ?";return jdbcTemplate.update(sql, user.getName(), user.getId());} }
-
在 MyBatis Mapper 接口的方法上使用(需谨慎)
虽然@DS
注解也可以用在 Mapper 接口上,但官方更推荐在 Service 层进行数据源切换。如果你确定要在 Mapper 层使用,可以像下面这样:
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import com.baomidou.dynamic.datasource.annotation.DS; import java.util.List;@Mapper public interface UserMapper {// 此查询使用 slave_1 数据源@DS("slave_1")@Select("SELECT * FROM user WHERE age > #{age}")List<User> selectUsersAboveAge(int age);// 此插入使用 master 数据源@DS("master")@Insert("INSERT INTO user (name, age) VALUES (#{name}, #{age})")int insertUser(User user); }
重要注意事项
-
注解失效的常见情况
-
事务内调用:最需要警惕的情况。在一个没有
@DS
注解(即使用默认数据源)的@Transactional
方法内部,调用另一个有@DS("slave_1")
注解的方法,被调用的方法并不会切换到slave_1
数据源,而是继续使用默认数据源。这是因为 Spring 的事务管理会先于数据源切换切面执行,在事务开始时就已经确定了数据源。 -
同类方法调用:在同一个 Service 类中,一个没有
@DS
注解的方法 A 直接调用另一个有@DS("slave_1")
注解的方法 B,方法 B 的注解也会失效。这是因为 Spring AOP 切面机制无法拦截类内部的自我调用。 -
解决方案:对于上述情况,通常可以将需要切换数据源的方法抽取到另一个独立的 Service 类中,然后通过注入调用,以确保 AOP 切面生效。
-
-
事务管理
多数据源环境下,需要仔细考虑事务的边界。@Transactional
注解默认使用主数据源的事务管理器。如果需要进行跨多个数据源的分布式事务,需要考虑集成如 Seata 等分布式事务解决方案,dynamic-datasource
也提供了基于 Seata 的集成方案。 -
连接池配置
你可以为每个数据源单独配置其连接池参数(如上面 YAML 配置示例中的druid
或hikari
节点),根据实际需求调整最大连接数、最小空闲数等。 -
避免在 Controller 中使用
数据源切换的逻辑应放在 Service 层,Controller 层不应关心数据源细节。 -
监控与健康检查
如果使用了 Druid 连接池,并配置了监控功能,需要注意监控页面的路径和配置可能也需要在多数据源环境下进行相应调整。