跨数据源查询:VD 设备列表的改造实践
前端视频巡查任务配置页需要展示”有视频设备的测站列表 + 每个测站下的设备”。但设备表在主库,测站表在 slave 库,无法一条 SQL JOIN。本文记录了使用 @DS 注解 + Java 内存组装的跨数据源查询方案。
🎧 文章导读
🎵 背景音乐
背景
视频巡查功能需要展示测站及其下的视频设备。数据分布在两个数据库中:
| 表 | 数据库 | 用途 |
|---|---|---|
bs_sw_cy_dh_equipmentb(设备表) |
主库 (gdsw) | 存储设备信息 |
st_stbprp_b(测站表) |
slave 库 (water) | 存储测站信息 |
由于两张表在不同的数据库中,无法使用 SQL JOIN,需要在 Java 层组装数据。
方案设计
使用 dynamic-datasource 的 @DS 注解切换数据源,两次查询 + Java 内存组装:
1 | 1. 查设备表(主库)→ 获取设备列表 |
核心实现

图1:跨数据源查询的三步流程
Step 1: 新建测站实体和 Mapper
1 | // StStbprpB.java - 测站实体 |
关键点:@DS("slave") 注解让这个 Mapper 的所有查询都走 slave 数据源。
Step 2: 修改设备 DTO
在 VdEquipment.java 中添加非数据库字段 stnm:
1 |
|
@TableField(exist = false) 告诉 MBP 这个字段不对应数据库列,避免映射错误。
Step 3: 实现跨数据源查询
1 |
|
查询优化
几个细节值得注意:
- 批量查询而非逐条查询——收集所有 stcd 后一次
IN查询,避免 N+1 问题 - 只查需要的字段——
select("STCD", "STNM")减少数据传输量 - 去重——
distinct()避免重复查询同一个测站 - 容错处理——
getOrDefault(e.getStcd(), null)处理测站不存在的情况
涉及文件汇总
| 操作 | 文件 | 说明 |
|---|---|---|
| 新建 | StStbprpB.java |
测站实体 |
| 新建 | StStbprpBMapper.java |
@DS(“slave”) 切换数据源 |
| 修改 | VdEquipment.java |
新增 stnm 字段 |
| 修改 | VdDeviceServiceImpl.java |
跨数据源查询逻辑 |
Controller 和 Service 接口不需要改,返回类型 IPage<VdEquipment> 不变。
跨数据源查询的几种方案对比

图2:四种跨数据源查询方案的优缺点对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| @DS 注解 + Java 组装 | 简单直观,MBP 原生支持 | 需要两次查询 | 数据量不大,关联逻辑简单 |
| 聚合视图/物化视图 | 一条 SQL 完成 | 需要 DBA 配置,实时性差 | 查询频繁,数据变化少 |
| 数据同步(ETL) | 查询性能最好 | 架构复杂,有延迟 | 数据量大,分析型查询 |
| 分布式查询引擎 | 统一 SQL | 引入新组件 | 多数据源场景多 |
本场景选择 @DS 注解方案,因为:
- 数据量不大(设备表几千条)
- 关联逻辑简单(只需回填测站名称)
- 不想引入额外组件
经验总结
- @DS 注解要加在 Mapper 上——加在 Service 上不生效,因为 MBP 的动态数据源是基于 Mapper 代理的
- 批量查询避免 N+1——先收集所有 ID,一次 IN 查询,而不是逐条查询
- 只查需要的字段——
select()减少数据传输量,尤其是大表 - 容错处理——关联数据可能不存在,用
getOrDefault处理
本文涉及代码在 digital-twin 模块中,已在 master-b_sp_20251216-delDec 分支提交。