在日常开发过程中,使用多个数据源已经成为一种常见需求。本文将详细介绍如何在SpringBoot项目中配置和使用多数据源,包括静态配置和动态配置两种方式,从而实现不同数据源的动态切换,以及在实际项目中进行使用并验证。
一、静态配置多数据源
1.添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- alibaba的druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.2.9.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
2.配置文件
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
db1:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/practice?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&generateSimpleParameterMetadata=true&autoReconnect=true&useSSL=true
username: root
password:
db2:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/practice_admin?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&generateSimpleParameterMetadata=true&autoReconnect=true&useSSL=true
username: root
password:
druid-pool:
#连接池的最大数据库连接数。设为0表示无限制
max-active: 20
#初始化数量
initial-size: 2
#最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制
max-wait: 60000
#最小空闲连接:连接池中容许保持空闲状态的最小连接数量,低于这个数量将创建新的连接
min-idle: 2
mybatis-plus:
mapper-locations: classpath*:mapper/*/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3.配置数据源
数据源1
@Configuration
@MapperScan(basePackages = "com.practice.mapper.db1", sqlSessionFactoryRef = "sqlSessionFactoryOne")
public class DataSourceConfigOne {
@Value("${spring.datasource.type}")
private Class<? extends DataSource> dataSourceType;
@Value("${spring.datasource.druid-pool.initial-size}")
private int initialSize;
@Value("${spring.datasource.druid-pool.max-active}")
private int maxActive;
@Value("${spring.datasource.druid-pool.max-wait}")
private int maxWait;
@Value("${spring.datasource.druid-pool.min-idle}")
private int minIdle;
@Primary
@Bean("dataSourceOne")
@ConfigurationProperties(prefix = "spring.datasource.db1")
public DataSource dataSourceOne() {
DruidDataSource druidDataSource = (DruidDataSource) DataSourceBuilder.create().type(dataSourceType).build();
druidDataSource.setMaxActive(maxActive);
druidDataSource.setMaxWait(maxWait);
druidDataSource.setInitialSize(initialSize);
druidDataSource.setMinIdle(minIdle);
return druidDataSource;
}
@Primary
@Bean("sqlSessionFactoryOne")
public SqlSessionFactory sqlSessionFactoryOne(@Qualifier("dataSourceOne") DataSource dataSourceOne) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSourceOne);
// 配置mapper对应xml文件位置
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/db1/*.xml"));
return sqlSessionFactoryBean.getObject();
}
@Primary
@Bean("sqlSessionTemplateOne")
public SqlSessionTemplate sqlSessionTemplateOne(@Qualifier("sqlSessionFactoryOne") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
这里简单介绍下DataSource
、SqlSessionFactory
和SqlSessionTemplate
DataSource
是一个接口,定义了一个类获取数据库连接的基本方法。在 Java 应用中,DataSource 通常由连接池来实现,像 HikariCP、Druid 等。它管理数据库连接的创建、管理和释放。SqlSessionFactory
是 MyBatis 中用于创建 SqlSession 实例的工厂。SqlSession 是 MyBatis 的一个核心类,用于执行 SQL 语句、获取映射器(mapper)实例以及管理事务。SqlSessionTemplate
是 Spring 对 MyBatis SqlSession 的实现。它负责管理 SqlSession 的生命周期,确保线程安全,并将异常转换为 Spring 的 DataAccessException。
数据源2和数据源1类似,只是关联的配置属性和对应Bean的名称不同
@Configuration
@MapperScan(basePackages = "com.practice.mapper.db2", sqlSessionFactoryRef = "sqlSessionFactoryTwo")
public class DataSourceConfigTwo {
@Value("${spring.datasource.type}")
private Class<? extends DataSource> dataSourceType;
@Value("${spring.datasource.druid-pool.initial-size}")
private int initialSize;
@Value("${spring.datasource.druid-pool.max-active}")
private int maxActive;
@Value("${spring.datasource.druid-pool.max-wait}")
private int maxWait;
@Value("${spring.datasource.druid-pool.min-idle}")
private int minIdle;
@Bean("dataSourceTwo")
@ConfigurationProperties(prefix = "spring.datasource.db2")
public DataSource dataSourceTwo() {
DruidDataSource druidDataSource = (DruidDataSource) DataSourceBuilder.create().type(dataSourceType).build();
druidDataSource.setMaxActive(maxActive);
druidDataSource.setMaxWait(maxWait);
druidDataSource.setInitialSize(initialSize);
druidDataSource.setMinIdle(minIdle);
return druidDataSource;
}
@Bean("sqlSessionFactoryTwo")
public SqlSessionFactory getSqlSessionFactoryTwo(@Qualifier("dataSourceTwo") DataSource dataSourceTwo) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSourceTwo);
// 配置mapper对应xml文件位置
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/db2/*.xml"));
return sqlSessionFactoryBean.getObject();
}
@Bean("sqlSessionTemplateTwo")
public SqlSessionTemplate getSqlSessionTemplateTwo(@Qualifier("sqlSessionFactoryTwo") SqlSessionFactory sqlSessionFactoryTwo) throws Exception {
return new SqlSessionTemplate(sqlSessionFactoryTwo);
}
}
在上面的数据源配置中,我们指定了数据源类型为DruidDataSource
,Druid是阿里巴巴开源的数据库连接池,具有功能丰富、监控强大、配置灵活等特点,适用于需要复杂功能和强大监控能力的场景。Spring Boot从2.x开始,如果没有指定数据源类型,默认会使用HikariCP
作为数据源实现,HikariCP连接池具有较低资源消耗和较高性能的特点,适用于性能要求高、轻量级的应用。
如果需要整合使用Mybatis-Plus,则需要添加对应的依赖,并对SqlSessionFactory做如下配置
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
@Bean("sqlSessionFactoryOne")
public SqlSessionFactory sqlSessionFactoryOne(@Qualifier("dataSourceOne") DataSource dataSourceOne) throws Exception {
MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
mybatisSqlSessionFactoryBean.setDataSource(dataSourceOne);
mybatisSqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/db1/*.xml"));
MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();
mybatisConfiguration.setLogImpl(StdOutImpl.class);
mybatisSqlSessionFactoryBean.setConfiguration(mybatisConfiguration);
return mybatisSqlSessionFactoryBean.getObject();
}
4.使用验证
在db1和db2中新建两张表:employee和sys_user,分别插入数据到employee和sys_user表中
CREATE TABLE `employee` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '员工姓名',
`code` varchar(100) NOT NULL COMMENT '员工编码',
`age` int(11) NOT NULL COMMENT '年龄',
`sub_company` varchar(100) NOT NULL COMMENT '子公司',
`job` varchar(100) DEFAULT NULL COMMENT '岗位',
`department` varchar(100) NOT NULL COMMENT '部门',
`salary` int(11) DEFAULT '0' COMMENT '工资',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_age_salary` (`age`,`salary`)
) ENGINE=InnoDB AUTO_INCREMENT= 1 DEFAULT CHARSET=utf8 COMMENT='员工表';
CREATE TABLE `sys_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_cd` varchar(128) NOT NULL COMMENT '用户编码',
`username` varchar(128) NOT NULL COMMENT '名称',
`password` varchar(128) NOT NULL COMMENT '密码',
`salt` varchar(128) NOT NULL COMMENT '盐值',
`status` tinyint(4) DEFAULT '1' COMMENT '状态 0-停用 1-启用',
`email` varchar(128) NOT NULL COMMENT '邮箱',
`phone` int(20) NOT NULL COMMENT '手机号',
`address` varchar(128) DEFAULT NULL COMMENT '地址',
`remark` varchar(256) DEFAULT NULL COMMENT '备注',
`del_flag` tinyint(4) NOT NULL DEFAULT '0',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_user_cd` (`user_cd`)
) ENGINE=InnoDB AUTO_INCREMENT= 1 DEFAULT CHARSET=utf8mb4 COMMENT='系统用户表';
在代码中添加对应的实体类、mapper接口和mapper.xml文件
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private EmployeeMapper employeeMapper;
@Autowired
private SysUserMapper sysUserMapper;
@GetMapping("/user")
public APIResponse getUser(@RequestParam Integer userId) {
return new APIResponse(sysUserMapper.getSysUserById(userId));
}
@GetMapping("/employee")
public APIResponse getEmployee(@RequestParam Integer employeeId) {
return new APIResponse(employeeMapper.getEmployeeById(employeeId));
}
}
在上面的代码中,我们将mapper对应的xml文件放在了resources目录下
有的时候会将其放在java目录下的mapper下,即:
由于Maven在build项目的时候,对于java目录下的文件,默认只会加载.java类型的,不会加载.xml文件,因此在构建完成后的target目录中找不到对应的xml文件。因此,这时除了需要修改数据源配置中mapperLocation的路径,还需要在pom.xml文件中加上如下配置,这样在构建项目的时候,java目录下的xml文件也会被加载。
<build>
<resources>
<resource>
<directory>${basedir}/src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<!-- 是否替换资源中的属性-->
<filtering>false</filtering>
</resource>
</resources>
</build>
最后分别调用测试接口,成功返回数据如下
{
"code": 0,
"message": "SUCCESS",
"data": {
"id": 1,
"name": "大壮",
"code": "DEV001",
"age": 28,
"subCompany": null,
"job": "研发",
"department": "研发一部",
"salary": 6000
}
}
{
"code": 0,
"message": "SUCCESS",
"data": {
"id": 1,
"userCd": null,
"username": "tom",
"password": "tom666",
"salt": "fsaf",
"status": 1,
"email": "tom666@qq.com",
"phone": "666",
"address": null,
"remark": null,
"delFlag": null
}
}
二、动态配置多数据源
1.配置文件
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
master:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/practice?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&generateSimpleParameterMetadata=true&autoReconnect=true&useSSL=true
username: root
password:
slave:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/practice_admin?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&generateSimpleParameterMetadata=true&autoReconnect=true&useSSL=true
username: root
password:
druid-pool:
#连接池的最大数据库连接数。设为0表示无限制
max-active: 20
#初始化数量
initial-size: 2
#最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制
max-wait: 60000
#最小空闲连接:连接池中容许保持空闲状态的最小连接数量,低于这个数量将创建新的连接
min-idle: 2
2.配置数据源
配置数据源基本信息,并将所有数据源添加到动态数据源中进行进行管理
@Configuration
public class DynamicDataSourceConfig {
@Value("${spring.datasource.type}")
private Class<? extends DataSource> dataSourceType;
@Value("${spring.datasource.druid-pool.initial-size}")
private int initialSize;
@Value("${spring.datasource.druid-pool.max-active}")
private int maxActive;
@Value("${spring.datasource.druid-pool.max-wait}")
private int maxWait;
@Value("${spring.datasource.druid-pool.min-idle}")
private int minIdle;
@Primary
@Bean("masterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
DruidDataSource druidDataSource = (DruidDataSource) DataSourceBuilder.create().type(dataSourceType).build();
druidPoolConfig(druidDataSource);
return druidDataSource;
}
@Bean("slaveDataSource")
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
DruidDataSource druidDataSource = (DruidDataSource) DataSourceBuilder.create().type(dataSourceType).build();
druidPoolConfig(druidDataSource);
return druidDataSource;
}
private void druidPoolConfig(DruidDataSource druidDataSource) {
druidDataSource.setMaxActive(maxActive);
druidDataSource.setMaxWait(maxWait);
druidDataSource.setInitialSize(initialSize);
druidDataSource.setMinIdle(minIdle);
}
@Bean("dataSource")
@DependsOn({"masterDataSource", "slaveDataSource"})
public DataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("slaveDataSource") DataSource slaveDataSource) {
Map<Object, Object> dataSourceMap = new HashMap<>();
dataSourceMap.put("masterDataSource", masterDataSource);
dataSourceMap.put("slaveDataSource", slaveDataSource);
DynamicDataSourceContextHolder.dataSourceNames.add("masterDataSource");
DynamicDataSourceContextHolder.dataSourceNames.add("slaveDataSource");
// 设置动态数据源
return new DynamicDataSource(masterDataSource, dataSourceMap);
}
}
public class DynamicDataSource extends AbstractRoutingDataSource {
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(targetDataSources);
}
@Override
public Object determineCurrentLookupKey() {
return DynamicDataSourceContextHolder.getDataSource();
}
}
自定义DynamicDataSouce并继承AbstractRoutingDataSource
。AbstractRoutingDataSource
是 Spring 框架中用于实现动态数据源路由的一个抽象类。它通过实现数据源的动态切换来支持多数据源的应用场景。AbstractRoutingDataSource
的核心原理是通过一个线程本地变量(ThreadLocal)来保存当前使用的数据源标识,然后在每次获取连接时,根据这个标识来决定使用哪个数据源。
主要方法包括:
- determineCurrentLookupKey():这是一个抽象方法,需要子类实现。它用于确定当前使用的数据源标识。根据返回的标识,
AbstractRoutingDataSource
会从预先配置的数据源中选择对应的数据源。 - setTargetDataSources():用于设置数据源的映射关系。这个方法接受一个
Map<Object, Object>
类型的参数,键为数据源标识,值为具体的数据源对象。 - setDefaultTargetDataSource():用于设置默认的数据源。如果没有找到匹配的数据源标识,就会使用默认的数据源。
- afterPropertiesSet():检查配置,确保
targetDataSources
和defaultTargetDataSource
属性已被设置;初始化映射,将指定的默认数据源和目标数据源映射解析并存储到相应的内部变量中。
public class DynamicDataSourceContextHolder {
private static final ThreadLocal<String> DATASOURCE_CONTEXT_HOLDER = new ThreadLocal<>();
/**
* 管理全部数据源
*/
public static List<String> dataSourceNames = new ArrayList<>();
/**
* 判断是否存在指定数据源
*/
public static boolean containsDataSource(String dataSourceName) {
return dataSourceNames.contains(dataSourceName);
}
/**
* 设置当前数据源
*/
public static void setDataSource(String dataSourceName) {
DATASOURCE_CONTEXT_HOLDER.set(dataSourceName);
}
/**
* 获取当前数据源
*/
public static String getDataSource() {
return DATASOURCE_CONTEXT_HOLDER.get();
}
/**
* 清除数据源
*/
public static void clear() {
DATASOURCE_CONTEXT_HOLDER.remove();
}
}
ThreadLocal是Java中的一个工具类,能够为每个线程提供一个独立的变量副本,从而实现线程隔离。利用ThreadLocal管理当前使用的数据源,DynamicDataSourceContextHolder可以在不同的线程间隔离数据源的使用,实现数据源的动态切换。
如果整合使用了Mybatis-Plus,则还需要添加Mybatis-Plus的相关配置,否则会报错,如下所示
@Configuration
@MapperScan(basePackages = {"com.practice.mapper"}, sqlSessionTemplateRef = "sqlTemplateDefault")
public class MybatisConfig {
@Bean(name = "sqlFactoryDefault")
public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource)
throws Exception {
MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
factoryBean.setDataSource(dynamicDataSource);
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
factoryBean.setMapperLocations(resolver.getResources("classpath*:mapper/*/*.xml"));
MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();
mybatisConfiguration.setLogImpl(StdOutImpl.class);
factoryBean.setConfiguration(mybatisConfiguration);
return factoryBean.getObject();
}
@Bean(name = "sqlTemplateDefault")
public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlFactoryDefault") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
3.利用AOP动态切换
自定义数据源标识注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DS {
String value() default "";
}
利用AOP实现动态切换数据源
@Component
@Aspect
@Slf4j
public class DynamicDataSourceAspect {
private static final String DEFAULT_DATASOURCE = "masterDataSource";
@Pointcut("@annotation(com.practice.annotation.DS)")
public void dsPointCut() {}
@Before("dsPointCut() && @annotation(ds)")
public void changeDataSource(JoinPoint joinPoint, DS ds) {
String dataSourceName = ds.value();
if (DynamicDataSourceContextHolder.containsDataSource(dataSourceName)) {
DynamicDataSourceContextHolder.setDataSource(dataSourceName);
log.info("切换到数据源:{}", dataSourceName);
} else {
log.error("数据源不存在:{}", dataSourceName);
}
}
@After("@annotation(ds)")
public void clearDataSource(JoinPoint joinPoint, DS ds) {
DynamicDataSourceContextHolder.clear();
}
}
4.使用验证
我们在上面的配置中让practice作为主库,practice_admin作为从库,分别在两个库中创建一张相同的sys_user表,并分别插入一条不同的数据
INSERT INTO practice.sys_user (user_cd, username, `password`, salt, email, phone, address)
VALUE ('A0001', '小明', 'dfefegegww3', 'gegsgegewxda', '184719579@qq.com', '12562658345', '北京市-海淀区');
INSERT INTO practice_admin.sys_user (user_cd, username, `password`, salt, email, phone, address)
VALUE ('A0001', '小刚', 'dasfsjefie', 'fejoijgefe', '184719579@qq.com', '17573458375', '北京市-朝阳区');
创建两个查询接口和一个插入接口进行测试,分别在两个查询接口添加@DS("masterDataSource")
和@DS("slaveDataSource")
,在新增接口上添加@DS("masterDataSource")
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private SysUserMapper sysUserMapper;
@GetMapping("/master/user")
@DS("masterDataSource")
public APIResponse getMasterUser(@RequestParam Integer userId) {
return new APIResponse(sysUserMapper.selectById(userId));
}
@GetMapping("/slave/user")
@DS("slaveDataSource")
public APIResponse getSlaveUser(@RequestParam Integer userId) {
return new APIResponse(sysUserMapper.selectById(userId));
}
@PostMapping("/user")
@DS("masterDataSource")
public APIResponse addUser(@RequestBody UserReq userReq) {
SysUser sysUser = new SysUser();
BeanUtils.copyProperties(userReq, sysUser);
return new APIResponse(sysUserMapper.insert(sysUser));
}
}
调用/master/user查询接口,返回如下
{
"code": 0,
"message": "SUCCESS",
"data": {
"id": 1,
"userCd": "A0001",
"username": "小明",
"password": "dfefegegww3",
"salt": "gegsgegewxda",
"status": 1,
"email": "184719579@qq.com",
"phone": "12562658345",
"address": "北京市-海淀区",
"remark": null,
"delFlag": 0
}
}
调用/slave/user查询接口,返回如下
{
"code": 0,
"message": "SUCCESS",
"data": {
"id": 1,
"userCd": "A0001",
"username": "小刚",
"password": "dasfsjefie",
"salt": "fejoijgefe",
"status": 1,
"email": "184719579@qq.com",
"phone": "17573458375",
"address": "北京市-朝阳区",
"remark": null,
"delFlag": 0
}
}
控制台日志如下:
2024-07-11 14:17:05.719 INFO 16184 --- [nio-8080-exec-1] c.p.aspect.DynamicDataSourceAspect : 切换到数据源:masterDataSource
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1725706d] was not registered for synchronization because synchronization is not active
2024-07-11 14:17:05.885 INFO 16184 --- [nio-8080-exec-1] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} inited
JDBC Connection [com.mysql.jdbc.JDBC4Connection@104bb573] will not be managed by Spring
==> Preparing: SELECT id,user_cd,username,password,salt,status,email,phone,address,remark,del_flag FROM sys_user WHERE id=?
==> Parameters: 1(Integer)
<== Columns: id, user_cd, username, password, salt, status, email, phone, address, remark, del_flag
<== Row: 1, A0001, 小明, dfefegegww3, gegsgegewxda, 1, 184719579@qq.com, 12562658345, 北京市-海淀区, null, 0
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1725706d]
2024-07-11 14:17:23.465 INFO 16184 --- [nio-8080-exec-2] c.p.aspect.DynamicDataSourceAspect : 切换到数据源:slaveDataSource
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5cbfb029] was not registered for synchronization because synchronization is not active
2024-07-11 14:17:23.474 INFO 16184 --- [nio-8080-exec-2] com.alibaba.druid.pool.DruidDataSource : {dataSource-2} inited
JDBC Connection [com.mysql.jdbc.JDBC4Connection@51ed3a8e] will not be managed by Spring
==> Preparing: SELECT id,user_cd,username,password,salt,status,email,phone,address,remark,del_flag FROM sys_user WHERE id=?
==> Parameters: 1(Integer)
<== Columns: id, user_cd, username, password, salt, status, email, phone, address, remark, del_flag
<== Row: 1, A0001, 小刚, dasfsjefie, fejoijgefe, 1, 184719579@qq.com, 17573458375, 北京市-朝阳区, null, 0
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5cbfb029]
综上可以看到,我们成功实现了动态的多数据源配置。