多数据源实现
# 多数据源实现
在实际开发中,经常遇到需要在一个应用中访问多个数据库的情况。若依框架通过配置多数据源,并使用注解的方式灵活切换数据源,以满足复杂的业务需求。本文将详细介绍在若依框架中如何实现多数据源的配置与使用,并包含注解的使用方法、手动切换数据源的操作,以及常见问题的解决方案。
# 一、@DataSource
注解参数说明
若依框架提供的 @DataSource
注解用于标注需要切换数据源的方法或类。通过配置注解参数,可以指定需要使用的数据源。
参数 | 类型 | 默认值 | 描述 |
---|---|---|---|
value | DataSourceType | DataSourceType.MASTER | 数据源类型,默认为主库 MASTER |
# 1. value
参数
value
参数用于指定数据源的名称。若依框架默认提供了 MASTER
和 SLAVE
数据源类型,开发者可以根据需要自行扩展其他数据源类型。
@DataSource(value = DataSourceType.SLAVE)
public List<SysUser> selectUserList(SysUser user)
{
return userMapper.selectUserList(user);
}
2
3
4
5
# 二、多数据源的配置与使用
# 1. 在 application-druid.yml
中配置从库数据源
首先,需要在 application-druid.yml
文件中配置从库的数据源。若依框架默认使用 Druid 数据库连接池,可以在此处定义多个数据源。
# 从库数据源
slave:
# 从数据源开关/默认关闭
enabled: true
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: password
2
3
4
5
6
7
# 2. 在 DataSourceType
类中添加数据源枚举
在 DataSourceType
枚举类中,添加对应的数据源类型枚举值。例如,添加 SLAVE
数据源类型。
public enum DataSourceType
{
MASTER, // 主库
SLAVE // 从库
}
2
3
4
5
# 3. 在 DruidConfig
中读取数据源配置
在 DruidConfig
配置类中,通过 @Bean
注解创建从库的数据源实例,并使用 @ConditionalOnProperty
注解控制从库数据源的启用条件。
@Bean
@ConfigurationProperties("spring.datasource.druid.slave")
@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
public DataSource slaveDataSource(DruidProperties druidProperties)
{
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
return druidProperties.dataSource(dataSource);
}
2
3
4
5
6
7
8
# 4. 在 DruidConfig
类的 dataSource
方法中添加数据源
在 dataSource
方法中,将从库的数据源添加到目标数据源集合中。
public DataSource dataSource()
{
Map<Object, Object> targetDataSources = new HashMap<>();
// 配置主库
targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource());
// 配置从库
targetDataSources.put(DataSourceType.SLAVE.name(), slaveDataSource());
// 动态数据源路由
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
dataSource.setDefaultTargetDataSource(masterDataSource()); // 设置默认数据源
dataSource.setTargetDataSources(targetDataSources); // 设置目标数据源
return dataSource;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# 5. 使用 @DataSource
注解切换数据源
在需要使用不同数据源的类或方法上,通过 @DataSource
注解指定数据源。
@DataSource(value = DataSourceType.SLAVE)
public List<SysUser> selectUserList(SysUser user)
{
return userMapper.selectUserList(user);
}
@Service
@DataSource(value = DataSourceType.SLAVE)
public class SysUserServiceImpl implements ISysUserService
{
// 服务实现代码
}
2
3
4
5
6
7
8
9
10
11
12
# 三、手动切换数据源
在某些复杂场景下,需要在同一方法中手动切换数据源。若依框架提供了 DynamicDataSourceContextHolder
类,支持手动切换数据源。
public List<SysUser> selectUserList(SysUser user)
{
// 手动切换到从库
DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.SLAVE.name());
List<SysUser> userList = userMapper.selectUserList(user);
// 清除数据源设置,恢复默认数据源
DynamicDataSourceContextHolder.clearDataSourceType();
return userList;
}
2
3
4
5
6
7
8
9
10
11
12
# 四、多数据源配置的逻辑实现
多数据源的核心逻辑通过 AOP 切面和动态数据源路由实现。在若依框架中,DataSourceAspect
切面类负责拦截标记了 @DataSource
注解的方法,并动态切换数据源。
# 1. DataSourceAspect
切面类
DataSourceAspect
切面类通过拦截标注了 @DataSource
注解的方法,解析注解参数,并调用 DynamicDataSourceContextHolder
切换数据源。
@Aspect
@Component
public class DataSourceAspect
{
@Before("@annotation(dataSource)")
public void beforeSwitchDS(JoinPoint point, DataSource dataSource)
{
// 切换数据源
DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
}
@After("@annotation(dataSource)")
public void afterSwitchDS(JoinPoint point, DataSource dataSource)
{
// 清除数据源设置,恢复默认数据源
DynamicDataSourceContextHolder.clearDataSourceType();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 2. 动态数据源路由
DynamicRoutingDataSource
类通过重写 determineCurrentLookupKey
方法,动态确定当前线程使用的数据源类型。
public class DynamicRoutingDataSource extends AbstractRoutingDataSource
{
@Override
protected Object determineCurrentLookupKey()
{
// 获取当前线程绑定的数据源类型
return DynamicDataSourceContextHolder.getDataSourceType();
}
}
2
3
4
5
6
7
8
9
# 五、常见问题与解决方案
# 1. Service 方法内多个注解无效
在 Service 方法内,如果有多个数据源切换注解无效的情况,可能是由于 Spring 的内部方法调用未触发 AOP 代理。解决方法是使用 SpringUtils.getAopProxy(this)
进行代理调用。
public void someServiceMethod()
{
// 使用 SpringUtils 获取 AOP 代理对象,并调用方法
SpringUtils.getAopProxy(this).methodWithDataSource();
}
2
3
4
5
# 2. 配置多个从库
若依框架支持配置多个从库,开发者可以在 application-druid.yml
中添加多个从库配置,并在 DataSourceType
枚举类中添加对应的数据源类型。
# 从库1数据源
slave1:
enabled: true
url: jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: password
# 从库2数据源
slave2:
enabled: true
url: jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: password
2
3
4
5
6
7
8
9
10
11
12
13
# 六、总结
通过配置多数据源并使用 @DataSource
注解,若依框架实现了灵活的多数据源管理,能够轻松应对多库操作的复杂场景。
- 多数据源配置: 在
application-druid.yml
中配置多个数据源,支持主库和多个从库。 - 注解切换数据源: 通过
@DataSource
注解在方法或类上切换数据源,简化代码编写。 - 手动切换数据源: 在复杂场景中,可以使用
DynamicDataSourceContextHolder
类手动切换数据源。 - 动态数据源路由: 通过
DynamicRoutingDataSource
类实现动态数据源路由,确保数据源切换的灵活性和高效性。