数据源之“多个数据源”
数据源是个象抽的接口,可以各种不同方式的玩转,容易混乱(尤其是"多数据源"和"动态数据源")。需要一些约定,把概念固定下来。
1、三个数据源概念约定
以数据源在“容器”里的记录为基准。设计这个概念约定。
概念 | 约定 |
---|---|
数据源 | 在容器里,会产生一个数据源的 Bean 记录。可以通过容器获取。 |
多个数据源 (或多数据源) | 在容器里,会产生多个数据源的 Bean 记录。可以通过容器获取。 |
子数据源 | 在一个数据源内部,还有二级数据源(也叫子数据源)。子数据源,不会在容器里有 Bean 记录。 |
2、其它数据源概念
分片数据源(内部有子数据源,基于分片规则切换):
- 是指一个数据源内有多个子数据源,根据规则确定相关数据源。一般用于分库分表或读写分离场景等。
- 比如:ShardingDataSource(基于 Apache ShardingSphere 适配的数据源)
动态数据源(内部有子数据源,基于线程状态切换):
- 是指一个数据源内有多个子数据源,且可以动态切换内部的子数据源。用时,需要不断手动指定。
- 比如:DynamicDataSource,参考插件 solon-data-dynamicds
- 一般通过:
@DynamicDs("db_user_1")
、@DynamicDs("db_user_2")
切换动态数据源内部的子数据源 - 一个应用里,只能有一个同类型的动态数据源!(否则,线程状态切换就错乱了)
3、“多数据源” 和 “动态数据源” 的区别
从技术上看 “分片数据源”、“动态数据源” 似乎也算 “多数据源”,内部都有多个子数据源。但,我们这里的 “多数据源” 以容器里的记录为准。
- 多数据源(或多个数据源)
是指在“容器”里有多个数据源的记录
- 动态数据源
动态数据源,在“容器”里只会有一个数据源的记录。但内部会有多个子数据源。一般,可以通过线程状态进行切换。
4、数据源的获取方式
获取方式:
方式 | 示例代码 |
---|---|
注入方式 | @Inject("db_order") |
同步获取方式 | Solon.context().getBean("db_order") |
异步获取方式 | Solon.context().getBeanAsync("db_order", ds->{ ... }) |
工具获取方式 | DsUtils.observeDs(Solon.context(), "db_order", dsWrap->{ ... }) |
获取子数据源的方式(以 DynamicDataSource 为例):
//选获取数据源
DynamicDataSource dds = Solon.context().getBean("db_user");
//再获取数据源内的子数据源
DataSource tmp = dds.getTargetDataSource("db_user_w");
获取默认数据源的方式:
方式 | 示例代码(按类型获取) |
---|---|
注入方式 | @Inject |
同步获取方式 | Solon.context().getBean(DataSource.class) |
异步获取方式 | Solon.context().getBeanAsync(DataSource.class, ds->{ ... }) |
工具获取方式 | DsUtils.observeDs(Solon.context(), "", dsWrap->{ ... }) |
5、获取一批数据源
//1.注入方式
@Inject
Map<String, DataSource> dsMap;
//2.订阅获取方式(可以源源不断,实时获取新建构的数据源)
Solon.context().subWrapsOfType(DataSource.class, dsWrap->{
//dsWrap.name(); //数据源名字
//dsWrap.typed(); //是否申明以类型注册的(相当于默认)
//dsWrap.raw(); //原始 DataSource 实例
});
//3.同步获取方式(要注意时机点)
Map<String, DataSource> dsMap = Solon.context().getBeansMapOfType(DataSource.class);
应用开发时,一般不会直接使用数据源对象,而是使用 ORM 的特定对象及增强注解。
6、插件适配指南(如何获取数据源)
工具 DsUtils.observeDs
:
/**
* @param dsName 数据源名(为空时,表过默认数据源)
*/
DsUtils.observeDs(appContext, dsName, (dsWrap) -> {
});
应用示例:
public class DbBeanInjectorImpl implements BeanInjector<Db> {
@Override
public void doInject(VarHolder vh, Db anno) {
//要求必须注入
vh.required(true);
//根据注解获取数据源
DsUtils.observeDs(vh.context(), anno.value(), (dsWrap) -> {
inject0(vh, dsWrap);
});
}
private void inject0(VarHolder vh, BeanWrap dsBw) {
//...
}
}