zsElectric-OpenApi 开放平台采用双数据库架构,将开放平台数据和业务系统数据进行物理隔离,同时通过动态数据源实现跨数据库访问。
这是开放平台专用的数据库,存储以下数据:
优点:
这是原有的业务系统数据库,开放平台通过动态数据源只读访问该数据库:
访问方式:
@DS("business") 注解指定数据源spring:
datasource:
dynamic:
primary: openapi # 默认使用开放平台数据库
strict: false
datasource:
# 开放平台独立数据库
openapi:
url: jdbc:mysql://localhost:3306/zs_electric_openapi
username: root
password: root
# 业务系统数据库(只读)
business:
url: jdbc:mysql://localhost:3306/zs_electric
username: root
password: root
spring:
datasource:
dynamic:
primary: openapi
datasource:
openapi:
url: jdbc:mysql://prod-db-host:3306/zs_electric_openapi
username: openapi_user # 专用账号,仅拥有openapi数据库权限
password: xxxxx
business:
url: jdbc:mysql://prod-db-host:3306/zs_electric
username: business_readonly_user # 只读账号
password: xxxxx
对于开放平台自己的实体类(如AppInfo、ApiLog),不需要任何注解:
@Data
@TableName("openapi_app_info")
public class AppInfo {
// 使用默认数据源(openapi)
}
@Mapper
public interface AppInfoMapper extends BaseMapper<AppInfo> {
// 使用默认数据源(openapi)
}
@Service
public class AppInfoService extends ServiceImpl<AppInfoMapper, AppInfo> {
// 使用默认数据源(openapi)
}
对于需要访问业务系统数据的实体类,使用 @DS("business") 注解:
@Data
@TableName("charging_station")
public class ChargingStation {
// 实体类定义
}
@Mapper
@DS("business") // 指定使用业务数据库
public interface ChargingStationMapper extends BaseMapper<ChargingStation> {
}
@Service
@DS("business") // Service层也指定
public class ChargingStationService extends ServiceImpl<ChargingStationMapper, ChargingStation> {
public List<ChargingStation> getActiveStations() {
// 查询业务数据库
return lambdaQuery()
.eq(ChargingStation::getStatus, 1)
.list();
}
}
Controller层直接调用对应的Service即可,数据源切换由Service层的注解控制:
@RestController
@RequestMapping("/api/v1/charging")
@RequiredArgsConstructor
public class ChargingController {
private final ChargingStationService chargingStationService; // 使用business数据源
private final ApiLogMapper apiLogMapper; // 使用openapi数据源
@GetMapping("/stations")
public Result<Map<String, Object>> getStationList() {
// 调用业务系统数据
List<ChargingStation> stations = chargingStationService.getActiveStations();
// 记录到开放平台数据库
ApiLog apiLog = new ApiLog();
// ... 设置日志信息
apiLogMapper.insert(apiLog);
return Result.success(stations);
}
}
com.zsElectric.openapi/
├── entity/ # 开放平台实体(使用openapi数据源)
│ ├── AppInfo.java
│ └── ApiLog.java
├── mapper/ # 开放平台Mapper(使用openapi数据源)
│ ├── AppInfoMapper.java
│ └── ApiLogMapper.java
├── business/ # 业务系统相关(使用business数据源)
│ ├── entity/
│ │ ├── ChargingStation.java
│ │ └── ChargingOrder.java
│ ├── mapper/
│ │ ├── ChargingStationMapper.java
│ │ └── ChargingOrderMapper.java
│ └── service/
│ ├── ChargingStationService.java
│ └── ChargingOrderService.java
└── controller/ # 控制器
├── ChargingController.java
└── OrderController.java
生产环境应为不同的数据库创建专门的账号:
-- 开放平台数据库账号
CREATE USER 'openapi_user'@'%' IDENTIFIED BY 'password';
GRANT SELECT, INSERT, UPDATE, DELETE ON zs_electric_openapi.* TO 'openapi_user'@'%';
-- 业务系统只读账号
CREATE USER 'business_readonly_user'@'%' IDENTIFIED BY 'password';
GRANT SELECT ON zs_electric.* TO 'business_readonly_user'@'%';
A: 考虑到安全性、性能和可维护性,开放平台应该有独立的数据库,同时通过动态数据源访问业务数据。
A: 不能。生产环境应该使用只读账号访问业务数据库,所有写操作都在开放平台自己的数据库中。
A: 不能在同一个方法中直接切换数据源。需要将不同数据源的操作拆分到不同的Service中。
A: 动态数据源切换的性能损耗非常小,可以忽略不计。通过连接池管理,可以保证高性能。
A: 如果需要跨数据源事务,建议使用分布式事务方案,如Seata。但对于开放平台场景,通常不需要跨数据源事务。