Nacos 默认数据源方言插件实现规范:内置数据库族、Mapper 覆盖与兼容性契约
【免费下载链接】nacosan easy-to-use dynamic service discovery, configuration and service management platform for building AI cloud native applications.项目地址: https://gitcode.com/GitHub_Trending/na/nacos
导读
本文聚焦 Nacos 随服务端发行包内置的数据源方言(Database Dialect)实现——位于plugin-default-impl/nacos-default-datasource-plugin模块,它是 数据源方言插件规范 的内置实现集合。通过本文你将掌握:Nacos 内置支持哪些数据库族、每个数据库族由哪些 Dialect 与表级 Mapper 组成、启动时如何通过配置选择数据库类型、以及这些内置实现在逻辑 schema、SQL 占位符、生成主键与 AI 资源 mapper 上的兼容性约束,从而能在实际部署中正确选型数据库并规避升级迁移风险。
范围:持久化兼容层而非资源语义层
内置数据源方言实现位于plugin-default-impl/nacos-default-datasource-plugin目录,随 Nacos 服务端发行包一起发布,提供数据库方言(dialect)和表级 mapper。它的定位是 数据源方言插件规范 的内置实现,本质上是持久化兼容层(persistence compatibility layer)。
一个关键边界是:默认实现集合不得引入数据库特有的资源语义。数据库差异只体现在 SQL 语法层面(分页、函数、生成主键、转义等),Nacos 的业务语义、资源身份、鉴权与领域行为统一由上层 repository 与领域模块负责,方言与 mapper 不做决定。
内置数据库类型与 SPI 注册
当前实现打包了四个数据库族,每个数据库族对应一个独立 Maven 子模块:
| 数据库类型 | Dialect provider | Mapper 包 |
|---|---|---|
derby | DerbyDatabaseDialect | impl.derby |
mysql | MysqlDatabaseDialect和DefaultDatabaseDialect | impl.mysql |
postgresql | PostgresqlDatabaseDialect | impl.postgresql |
oracle | OracleDatabaseDialect | impl.oracle |
以源码印证(路径均在plugin-default-impl/nacos-default-datasource-plugin下):
nacos-datasource-plugin-derby/.../impl/dialect/DerbyDatabaseDialect.java:继承AbstractDatabaseDialect,getType()返回DatabaseTypeConstant.DERBY,getFunction()委托给TrustedDerbyFunctionEnum;nacos-datasource-plugin-mysql/.../impl/dialect/MysqlDatabaseDialect.java:getType()返回MYSQL,函数映射委托给TrustedMysqlFunctionEnum;同一模块还包含DefaultDatabaseDialect,因此 MySQL 族同时注册两个 Dialect provider;nacos-datasource-plugin-postgresql/.../impl/dialect/PostgresqlDatabaseDialect.java:除函数映射外,还重写了isDuplicateKeyException与分页 SQL(详见下文);nacos-datasource-plugin-oracle/.../impl/dialect/OracleDatabaseDialect.java:对应TrustedOracleFunctionEnum。
规范要求:每个数据库包必须同时注册两个 SPI 文件,即com.alibaba.nacos.plugin.datasource.dialect.DatabaseDialect和com.alibaba.nacos.plugin.datasource.mapper.Mapper。这在实际资源文件中得到确认,例如nacos-datasource-plugin-mysql/src/main/resources/META-INF/services/下:
com.alibaba.nacos.plugin.datasource.dialect.DatabaseDialect内容为DefaultDatabaseDialect与MysqlDatabaseDialect两个类全名;com.alibaba.nacos.plugin.datasource.mapper.Mapper内容为 9 个 mapper 实现类全名(见下一节)。
其余三个数据库族(derby / postgresql / oracle)在各自模块的src/main/resources/META-INF/services/下同样各含这两个 SPI 文件。
nacos-datasource-plugin-base子模块则承载各数据库族共享的基础设施:AbstractDatabaseDialect(默认分页与主键行为)、BaseConfigInfoMapper、BaseConfigTagsRelationMapper、BaseGroupCapacityMapper、BaseTenantCapacityMapper、BaseTenantInfoMapper等 base mapper,以及TrustedPostgresqFunctionEnum枚举。
Mapper 覆盖范围
每个内置数据库族都应提供以下 mapper 实现:
- 当前配置表:
config_info、config_info_gray、config_tags_relation、his_config_info; - 容量与命名空间表:
tenant_info、tenant_capacity、group_capacity; - AI Registry 表:AI 资源元数据(
AiResourceMapper)和 AI 资源版本(AiResourceVersionMapper)。
源码逐一对应:以 MySQL 族为例,nacos-datasource-plugin-mysql/.../impl/mysql/下包含ConfigInfoMapperByMySql、ConfigInfoGrayMapperByMySql、ConfigTagsRelationMapperByMySql、HistoryConfigInfoMapperByMySql、TenantInfoMapperByMySql、TenantCapacityMapperByMysql、GroupCapacityMapperByMysql、AiResourceMapperByMySql、AiResourceVersionMapperByMySql共 9 个实现,且全部登记在 Mapper SPI 文件中。Derby、PostgreSQL、Oracle 族在各自impl.derby、impl.postgresql、impl.oracle包下有结构完全对称的实现集合。
此外,测试目录中存在*MapperCoverageTest(如MySqlMapperCoverageTest、OracleMapperCoverageTest、PostgresqlMapperCoverageTest、DerbyMapperCoverageTest),以及*AiResourceSearchSchemaResourceTest、*VisibilityPermissionSchemaResourceTest等 schema 资源测试,从测试侧保证了 mapper 覆盖的完整性与资源模型对齐。
3.3 版本线的迁移要求
从 Nacos 3.3 版本线开始,内置数据库族不再要求提供两类运行时 Config 迁移 mapper:
- 默认 namespace 存储重复记录的迁移;
- legacy beta/tag 灰度表(
config_info_beta、config_info_tag)的迁移。
因此,仍携带 pre-3.0config_info_beta或config_info_tag数据的部署,必须在升级到依赖当前 mapper 集合的 3.3 服务端之前完成数据迁移,迁移是升级前置动作,而不是服务端运行时 mapper 的职责。PostgreSQL 族的测试中专门存在PostgresqlTenantMigrationScriptTest,可见迁移脚本与测试是受控管理的。
另一个前瞻性约定:如果未来 Nacos 版本新增持久化表,内置数据库族必须在该表成为文档化服务端能力之前补充对应 mapper——即 mapper 覆盖永远先于对外发布。
启动选择:方言类型配置与历史 alias
Nacos 在启动时通过nacos.plugin.datasource-dialect.type选择数据库类型:
nacos.plugin.datasource-dialect.type=${databaseType}其中${databaseType}取derby、mysql、postgresql或oracle之一。
选择规则要点:
spring.sql.init.platform继续作为历史 alias兼容;二者同时存在时标准 keynacos.plugin.datasource-dialect.type优先;- 不再支持
spring.datasource.platform,该配置项已移除、不再读取; - 选择类型为
mysql时,使用 MySQL mapper 与 MySQL 兼容的默认 dialect 行为(这正是DefaultDatabaseDialect存在的意义); - 选择类型为
derby时,Derby 仍是 standalone 开发和本地测试的嵌入式默认数据库; - 当标准 key 与历史 alias 均未配置时,沿用服务端存储默认值:单机模式以及配置了
-DembeddedStorage=true的集群模式选择derby,普通集群模式选择mysql。
配置文件实证:在 distribution/conf/application.properties 中可以看到标准配置骨架:
# The database dialect selected at startup. Legacy spring.sql.init.platform remains supported. # nacos.plugin.datasource-dialect.type=mysql # spring.sql.init.platform=mysql同时该文件还给出了 datasource 模块配置(如nacos.plugin.datasource.db.num、nacos.plugin.datasource.db.url.0、nacos.plugin.datasource.db.user、nacos.plugin.datasource.db.password、nacos.plugin.datasource.db.query-timeout),并注明当标准 key 与历史写法并存时,nacos.plugin.datasource.db.*优先。
需要特别说明的是,方言类型属于互斥选择插件,selector 只提供启动选择、需要重启生效;该类型的持久化状态不能替代静态选择,运行时 status API 必须拒绝选择变更。
兼容性约束与内置方言的 critical 语义
内置实现必须遵守以下兼容性契约:
- 保持 Nacos 逻辑 schema:不同数据库族之间表名与列语义保持一致,不得因数据库差异改变逻辑 schema 或 资源模型;
- 保持 SQL 占位符与参数顺序:与 repository 代码兼容,运行时值使用占位符 SQL;
- 保持插入操作期望的生成主键列:方言通过
getReturnPrimaryKeys()返回生成主键列(AbstractDatabaseDialect返回PrimaryKeyConstant.LOWER_RETURN_PRIMARY_KEYS); - 保持 AI 资源 mapper 行为与资源模型对齐;
- 当某个数据库族需要 schema 变化时,补充迁移说明。
critical 状态语义
datasource-dialect类型加载后属于critical:当前选中的内置方言不能通过运行时插件状态禁用;但其他已加载的内置方言不会仅因为存在就分别成为 critical。也就是说,critical 属性绑定在被选中的那个方言上,而非所有已发现方言。
方言不持有数据源连接配置
内置方言实现不持有数据源连接或连接池配置。它们通过DatabaseDialect继承PluginConfigSpec,但不声明 definitions,因此以configurable=false暴露。原因是连接凭据和连接池参数属于服务端唯一数据源,而不是分别属于每个已加载方言;datasource 模块配置由上层 数据源方言插件规范 定义,统一使用nacos.plugin.datasource.db.{item}前缀。
分页与重复键判定的方言差异(源码级示例)
AbstractDatabaseDialect提供了 MySQL 风格默认实现:getLimitTopSqlWithMark返回sql + " LIMIT ? ",getLimitPageSqlWithMark返回sql + " LIMIT ?,? ",getLimitPageSql返回LIMIT offset, size。PostgreSQL 方言则在 PostgresqlDatabaseDialect.java 中重写为OFFSET ? LIMIT ?语法——这正是“同一逻辑操作、不同方言 SQL”的典型体现。
在唯一键冲突判定上,父规范定义了统一入口isDuplicateKeyException(Throwable):默认实现遍历异常因果链识别 SpringDuplicateKeyException,并通过类名匹配避免数据源插件模块引入 Spring 依赖;同时刻意不将裸的厂商 SQLState 本身当作重复。PostgreSQL 方言在此基础上进一步检查驱动抛出的SQLException的 SQLState 是否为23505(unique_violation),从而覆盖 Spring 异常转换不够精确的场景,代码如下:
private static final String UNIQUE_VIOLATION_SQL_STATE = "23505"; @Override public boolean isDuplicateKeyException(Throwable throwable) { if (super.isDuplicateKeyException(throwable)) { return true; } Throwable cause = throwable; while (cause != null) { if (cause instanceof SQLException && UNIQUE_VIOLATION_SQL_STATE.equals(((SQLException) cause).getSQLState())) { return true; } cause = cause.getCause(); } return false; }分类必须保持保守——非重复的完整性约束失败不得被误报为重复。对应的PostgresqlDatabaseDialectTest与各Trusted*FunctionEnumTest从测试侧锁定了这些行为。
小结
Nacos 默认数据源方言插件实现以“一套逻辑 schema + 多数据库方言”为核心设计:DerbyDatabaseDialect、MysqlDatabaseDialect/DefaultDatabaseDialect、PostgresqlDatabaseDialect、OracleDatabaseDialect分别对应四个内置数据库族,每个族通过DatabaseDialect与Mapper双 SPI 文件注册完整的表级 mapper(配置、灰度、标签、历史、命名空间、容量与 AI Registry 表)。部署时通过nacos.plugin.datasource-dialect.type静态选择数据库类型,未配置时按单机/集群模式隐式回退derby/mysql;升级到 3.3 前必须完成 pre-3.0config_info_beta/config_info_tag数据迁移。理解这些边界(逻辑 schema 稳定、占位符与参数顺序兼容、生成主键保留、critical 只绑定选中方言、方言不持有连接配置),是正确选型与平滑升级 Nacos 持久层的前提。
延伸阅读
- 数据源方言插件规范:本实现的上层父规范,涵盖 SPI 方法要求、选择与状态规则、完整的 datasource 模块配置表;
- 资源模型:AI 资源 mapper 行为对齐的语义基础;
- 持久化与 Dump 规范:持久化与 dump 边界定义;
- 源码实现:nacos-default-datasource-plugin 模块(含 base / derby / mysql / oracle / postgresql 五个子模块及其测试);
- 配置示例:distribution/conf/application.properties。
【免费下载链接】nacosan easy-to-use dynamic service discovery, configuration and service management platform for building AI cloud native applications.项目地址: https://gitcode.com/GitHub_Trending/na/nacos
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考