1、在项目中添加相关依赖,修改 pom.xml 文件以引入所需组件。
<!-- 动态数据源依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.6.1</version>
</dependency>
2、配置 application.yml 文件,设置多数据源的相关参数。
spring:
datasource:
dynamic:
primary: primary # 指定默认数据源
datasource:
# 第一个数据源(默认)
primary:
url: jdbc:mysql://127.0.0.1:22377/dade_py?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
# 第二个数据源
second:
url: jdbc:mysql://【第二个数据库IP】:【端口】/【数据库名】?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true
username: 【第二个数据库用户名】
password: 【第二个数据库密码】
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
maximum-pool-size: 15
minimum-idle: 3
connection-timeout: 30000
idle-timeout: 600000
3、通过注解方式实现数据源的切换。只需在 Service 类或具体方法上使用 @DS 注解,即可指定对应的数据源。
import com.baomidou.dynamic.datasource.annotation.DS;
import org.springframework.stereotype.Service;
@Service
public class TestService {
// 使用默认数据源(primary)
public void testPrimaryDb() {
// ... 操作默认数据库
}
// 切换到第二个数据源(second)
@DS("second")
public void testSecondDb() {
// ... 操作第二个数据库
}
}
4、若希望整个 Service 类中的所有方法均使用同一数据源,可将 @DS 注解直接标注在类上。
@Service
@DS("second") // ???? 类上注解:该类所有方法默认使用 second 数据源
public class SecondDbService {
private final UserMapper userMapper;
public SecondDbService(UserMapper userMapper) {
this.userMapper = userMapper;
}
// 无需单独加注解,自动使用 second 数据源
public List<User> getUserList() {
return userMapper.selectList(null);
}
}
5、当某个 Service 方法需要同时访问多个数据源时(例如从 primary 数据源查询数据,并插入到 second 数据源),仅使用 @DS 注解无法满足需求。此时需借助 DynamicDataSourceContextHolder 手动管理数据源上下文切换。
@Service
public class DataSyncService {
private final UserMapper userMapper;
private final OrderMapper orderMapper;
public DataSyncService(UserMapper userMapper, OrderMapper orderMapper) {
this.userMapper = userMapper;
this.orderMapper = orderMapper;
}
public void syncData() {
// 1. 用默认数据源(primary)查询数据
List<User> userList = userMapper.selectList(null);
// 2. 手动切换到 second 数据源(try-finally 确保切换后恢复)
DynamicDataSourceContextHolder.push("second");
try {
// 执行 SQL:使用 second 数据源
orderMapper.batchInsert(userList);
} finally {
// 3. 恢复默认数据源(必须执行,避免污染上下文)
DynamicDataSourceContextHolder.poll();
}
}
}
6、关于 Mapper 接口的设计:每个 Mapper 应固定绑定一个数据源。若涉及两个数据库,则应分别创建两个独立的 Mapper 接口。
默认数据源对应的 Mapper 配置如下:
package com.dao;
import com.baomidou.dynamic.datasource.annotation.DS;
import org.apache.ibatis.annotations.*;
import java.util.List;
import java.util.Map;
/**
* 使用默认数据源
* */
@DS("primary")
@Mapper
public interface CommonMapper {
@Select("${sql}")
public List<Map<String,Object>> query(@Param("sql")String sql);
@Select("${sql}")
public String querycode(@Param("sql")String sql);
@Insert("${sql}")
public int insert(@Param("sql")String sql);
@Update("${sql}")
public Integer update(@Param("sql")String sql);
@Delete("${sql}")
public Boolean del(@Param("sql")String sql);
/**
* LAST_INSERT_ID()
* 客户端返回的值是该客户端产生对影响AUTO_INCREMENT列的最新语句第一个 AUTO_INCREMENT值的。这个值不能被其它客户端影响,即使它们产生它们自己的 AUTO_INCREMENT值。这个行为保证了你能够找回自己的 ID 而不用担心其它客户端的活动,而且不需要加锁或处理
* */
@Select("SELECT LAST_INSERT_ID()")
public int id();
/**
* 开启事务
* */
@Select("START TRANSACTION")
public Boolean TRANSACTION();
/**
* 提交事务
* */
@Select("COMMIT")
public Boolean COMMIT();
/**
* 回滚事务
* */
@Select("ROLLBACK")
public Boolean ROLLBACK();
}
另一个数据源的 Mapper 配置示例如下:
package com.dao;
import com.baomidou.dynamic.datasource.annotation.DS;
import org.apache.ibatis.annotations.*;
import java.util.List;
import java.util.Map;
/**
* 使用second数据源
* */
@DS("second")
@Mapper
public interface CommonSecondMapper {
@Select("${sql}")
public List<Map<String,Object>> query(@Param("sql")String sql);
@Select("${sql}")
public String querycode(@Param("sql")String sql);
@Insert("${sql}")
public int insert(@Param("sql")String sql);
@Update("${sql}")
public Integer update(@Param("sql")String sql);
@Delete("${sql}")
public Boolean del(@Param("sql")String sql);
/**
* LAST_INSERT_ID()
* 客户端返回的值是该客户端产生对影响AUTO_INCREMENT列的最新语句第一个 AUTO_INCREMENT值的。这个值不能被其它客户端影响,即使它们产生它们自己的 AUTO_INCREMENT值。这个行为保证了你能够找回自己的 ID 而不用担心其它客户端的活动,而且不需要加锁或处理
* */
@Select("SELECT LAST_INSERT_ID()")
public int id();
/**
* 开启事务
* */
@Select("START TRANSACTION")
public Boolean TRANSACTION();
/**
* 提交事务
* */
@Select("COMMIT")
public Boolean COMMIT();
/**
* 回滚事务
* */
@Select("ROLLBACK")
public Boolean ROLLBACK();
}
实际使用时的调用方式如下所示:
package com.service.impl;
import com.dao.CommonMapper;
import com.dao.CommonSecondMapper;
import com.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Service
public class AdminServiceImpl implements AdminService {
@Autowired
private CommonMapper commonMapper;
@Autowired
private CommonSecondMapper commonSecondMapper;
@Override
public List<Map<String,Object>> query(String table, Map<String, Object> params) {
List<Map<String,Object>> datas = commonMapper.query("select * from dade");
List<Map<String,Object>> user = commonSecondMapper.query("select * from users");
System.out.println(datas);
System.out.println(user);
return datas;
}
}
