Nacos 3.1.0适配达梦数据库:SPI插件与SQL迁移实战

发布时间:2026/9/18 17:55:35
Nacos 3.1.0适配达梦数据库:SPI插件与SQL迁移实战 最近在做Nacos 3.1.0的国产数据库适配把配置中心的存储从MySQL切到了达梦。整个过程比想象中麻烦但也比想象中有章法——麻烦在于Nacos默认只认MySQL的SQL方言有章法在于它从2.2开始就留了数据源SPI扩展口子。这篇文章把我实测下来的适配路线、脚本迁移细节、SPI插件写法和几个埋得很深的坑整理出来给后面要接达梦、人大金仓或者其他国产库的同学一个参考。1. Nacos 3.1.0为什么要做数据库适配适配的是什么1.1 很多人误以为“外部存储支持任意数据库”Nacos安装完成后默认用内嵌Derby存储配置数据生产环境通常会把配置存储切到外部数据库。这里有一个很常见的误区以为把spring.datasource.platform改成对应数据库名再改一下连接串就能跑。实际上Nacos服务端的外部数据源支持一直是有边界的——官方开箱即用的只有MySQL其他数据库要么走社区插件要么自己适配。达梦数据库很多人叫它DM8它对MySQL的兼容性做得还行但远没到“零改动直接跑”的程度。Nacos 3.1.0内部使用MyBatis作为持久层框架SQL语句按MySQL方言编写分页、主键生成、函数调用都带着MySQL的影子。要让它在达梦上跑起来核心工作其实就是两件事换掉JDBC驱动、改掉SQL方言。1.2 Nacos的数据源扩展机制与两个适配层次Nacos从2.2版本开始引入了数据源插件机制服务端通过一组SPI接口抽象了不同数据库的差异。这个机制在3.x里延续了下来3.1.0也不例外。数据源相关代码主要在nacos-datasource-plugin-ext这类模块下核心接口大致是这样DataSourceService负责创建真实的数据源Connection对应不同数据库的驱动加载和连接池初始化。DatabaseDialect负责输出当前数据库的方言信息比如数据库类型标识、分页SQL生成、一部分自动转换逻辑。Nacos服务端启动时会根据配置的平台名称通过SPI找到对应的DataSourceService实现并加载。默认实现里只有MySQL和Derby所以想让3.1.0支持达梦本质就是提供一个达梦的DataSourceService实现再提供一个达梦的DatabaseDialect实现通过SPI注册进去。理解了这个机制就不会被网上各种“改源码重新编译”的教程带偏。改源码确实能跑但后续升级Nacos版本时要反复打Patch非常痛苦。走SPI插件路线Nacos主程序一行不动升级时只要用新版本重新编译一遍插件就行代价小很多。1.3 适配范围配置中心强依赖数据库服务发现不强依赖开始动手前需要搞清楚一个问题Nacos适配数据库主要影响哪个功能模块Nacos的服务注册与发现核心数据服务实例、健康状态、临时实例都保存在内存中底层有Raft协议做多节点同步这部分并不依赖外部数据库。真正强依赖外部数据库的是配置中心config_info、his_config_info、tenant_info、users这些表承载了配置内容、历史版本、租户信息和用户权限一旦数据库不可用配置中心基本就废了。所以适配达梦时回归测试的重点应该放在配置中心相关功能上服务发现的回归相对简单注册几个服务、确认心跳正常就行。这能省下不少测试时间。2. 达梦实例准备版本、兼容模式与账号权限2.1 达梦8的MySQL兼容模式能帮到什么达梦数据库在初始化实例或创建数据库时可以选择兼容模式常见的有Oracle兼容模式和MySQL兼容模式。Nacos的脚本和SQL都是MySQL方言所以选MySQL兼容模式是最优解这样大部分基础语法能被达梦直接映射比如反引号、DATETIME、LIMIT这些在兼容模式下支持度会好很多。不过要有个心理预期兼容模式不等于“完全兼容”。我实测下来达梦8的MySQL兼容模式能处理好80%的MySQL语法剩下的20%仍然要靠手工改造尤其集中在表注释、自增列、大字段这几种写法上。这是本章节后面要重点展开的内容。如果你手头的达梦实例不是MySQL兼容模式就会遇到比较棘手的情况建表时DATETIME类型可能直接报错AUTO_INCREMENT关键字的处理方式也会不一样。建议如果条件允许重新初始化一个MySQL兼容模式的达梦实例后面能少踩一半的坑。2.2 账号、模式和权限的最小规划达梦的账号体系有点介于Oracle和MySQL之间一个用户默认对应一个同名Schema。Nacos连接数据库后执行的所有SQL默认都在当前用户对应的Schema下进行。所以规划账号时要让Nacos使用的数据库账号和建表所在的Schema保持一致。我常用的建库方式是这样CREATE TABLESPACE nacos DATAFILE /opt/dmdbms/data/DAMENG/nacos.dbf SIZE 128 AUTOEXTEND ON NEXT 8 MAXSIZE 2000; CREATE USER nacos IDENTIFIED BY Nacos123 DEFAULT TABLESPACE nacos; GRANT DBA TO nacos;这里直接给了DBA权限纯粹是为了快速验证适配可行性生产环境建议收敛到RESOURCE、CREATE SESSION这类最小权限集然后按实际报错逐步补权限。给应用账号DBA权限在生产上风险太大不值得。需要注意达梦默认端口是5236连接串是jdbc:dm://127.0.0.1:5236/NACOS最后一个路径上的NACOS是Schema名要和建表时使用的Schema大小写保持一致否则启动后会报错“表或视图不存在”。3. 把mysql-schema.sql迁移到达梦逐条改造的细节3.1 建表DDL的方言改造对照Nacos 3.1.0的安装包中conf目录下自带mysql-schema.sql和derby-schema.sql两份脚本。我们要做的是把mysql-schema.sql改造成达梦可执行的dm-schema.sql。Nacos配置中心涉及的核心表包括config_info、config_info_gray、config_info_beta、config_info_tag、config_relation、group_capacity、his_config_info、tenant_capacity、tenant_info、users、roles、permissions、app_configdata_relation_subs。3.1.0相比2.x多了config_info_gray这张表用于灰度配置改造时别漏掉。以config_info表为例官方MySQL脚本大概长这样CREATE TABLE config_info ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT id, data_id varchar(255) NOT NULL COMMENT 配置id, group_id varchar(255) DEFAULT NULL, content longtext NOT NULL COMMENT 配置内容, md5 varchar(32) DEFAULT NULL COMMENT md5值, gmt_create datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, gmt_modified datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, src_user text, src_ip varchar(50) DEFAULT NULL, app_name varchar(128) DEFAULT NULL, tenant_id varchar(128) DEFAULT COMMENT 租户字段, c_desc varchar(256) DEFAULT NULL, c_use varchar(64) DEFAULT NULL, effect varchar(64) DEFAULT NULL, type varchar(64) DEFAULT NULL, c_schema text, encrypted_data_key text NOT NULL COMMENT 秘钥, PRIMARY KEY (id), UNIQUE KEY uk_configinfo_datagrouptenant (data_id,group_id,tenant_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_bin COMMENTconfig_info;改造后达梦可执行的版本CREATE TABLE config_info ( id BIGINT NOT NULL IDENTITY(1,1), data_id VARCHAR(255) NOT NULL, group_id VARCHAR(255), content CLOB NOT NULL, md5 VARCHAR(32), gmt_create TIMESTAMP DEFAULT CURRENT_TIMESTAMP, gmt_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP, src_user CLOB, src_ip VARCHAR(50), app_name VARCHAR(128), tenant_id VARCHAR(128) DEFAULT , c_desc VARCHAR(256), c_use VARCHAR(64), effect VARCHAR(64), type VARCHAR(64), c_schema CLOB, encrypted_data_key CLOB, CONSTRAINT pk_config_info PRIMARY KEY (id), CONSTRAINT uk_configinfo_datagrouptenant UNIQUE (data_id, group_id, tenant_id) ); COMMENT ON COLUMN config_info.id IS id; COMMENT ON COLUMN config_info.data_id IS 配置id; COMMENT ON COLUMN config_info.content IS 配置内容; COMMENT ON COLUMN config_info.tenant_id IS 租户字段; COMMENT ON COLUMN config_info.encrypted_data_key IS 秘钥;逐条说明一下改动逻辑MySQL的bigint(20) NOT NULL AUTO_INCREMENT改成了达梦的BIGINT NOT NULL IDENTITY(1,1)。IDENTITY(1,1)是达梦的自增列标准写法起始值和步长都是1。longtext和text全部改成了CLOB。这是达梦对应大文本字段的标准类型Nacos的content字段和encrypted_data_key字段都是存大段配置内容的如果保持VARCHAR很容易在写入大批量配置时报长度超限。datetime DEFAULT CURRENT_TIMESTAMP改成TIMESTAMP DEFAULT CURRENT_TIMESTAMP。达梦的MySQL兼容模式下DATETIME通常也能识别但用TIMESTAMP更稳妥。表级COMMENT xxx不能放在括号里达梦的写法是单独一行COMMENT ON COLUMN ... IS xxx。最后那句ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_bin直接删掉达梦没有存储引擎概念字符集在创建数据库实例时已经定了不需要在表结构里再声明。唯一约束用CONSTRAINT uk_... UNIQUE (...)替代MySQL的UNIQUE KEY uk_... (...)写法。其他表基本都是同样的套路。his_config_info、config_info_beta、config_info_gray这些表的字段结构高度相似复制config_info的改法就行。3.2 索引、约束与初始化数据的执行顺序MySQL脚本里常常会有这种写法KEY idx_configinfo_tenant_id (tenant_id)这种行内索引定义在达梦里不认。改造时把这种KEY都剔出来在CREATE TABLE语句执行成功后再单独建。比如CREATE INDEX idx_configinfo_tenant_id ON config_info(tenant_id);顺序很重要。建完所有表、做完所有索引和约束之后再执行初始化数据的INSERT语句。Nacos的mysql-schema.sql里带了一部分初始化数据包括管理员账号nacos/nacos初始密码的BCrypt哈希以及默认的roles、permissions记录。漏掉这些控制台登录会成为第一个拦路虎。执行方式上建议直接在达梦的disql命令行里执行disql nacos/Nacos123127.0.0.1:5236 start /opt/nacos/conf/dm-schema.sql或者用达梦自带的图形管理工具直接跑整个脚本。脚本执行前先开启事务一旦某一条DDL失败立即回滚逐段排查不要带着半截状态往下走。特别是外键和索引前面的表没建成功后面的约束就会报错而且报错信息往往让人摸不着头脑。3.3 INSERT语句里的隐藏雷点初始化数据里还有两个小细节容易被忽略。第一个是users表的enabled字段MySQL写法是TRUE/FALSE达梦里如果兼容模式没完全生效可能需要改成1/0。第二个是密码哈希值mysql-schema.sql中nacos用户的初始密码哈希是$2a$10$...格式这是一个BCrypt哈希达梦的VARCHAR字段长度够用但执行时要注意字符串里的$符号不要被命令行特殊转义。建议把INSERT语句单独存成一个init.sql文件用disql的start命令执行避免手工复制粘贴时丢字符。4. 不经源码重编译的SPI数据源插件驱动与方言4.1 为什么选SPI而不是直接改源码网上搜Nacos适配达梦能看到不少“修改源码、替换驱动、重新编译”的教程。这条路不是不能走但有个很现实的问题Nacos 3.x的迭代速度不慢今天你基于3.1.0改了源码明天官方发了3.1.1修复了一个安全漏洞你升级的时候就要把所有Patch重新打一遍。如果改动还涉及核心的ExternalDataSourceServiceImpl这类类每次升级都是煎熬。SPI插件方案没这个烦恼。Nacos主程序的jar包完全不动所有差异逻辑都收敛到独立的插件jar包中。升级Nacos时只需要用新版本的SPI接口重新编译插件即可。这也是Nacos官方推荐的扩展方式社区里很多数据库适配插件都是这么做的。4.2 DmDataSourceService与DmDialect的实现要点插件模块的代码结构大致如下nacos-dm-datasource-plugin/ pom.xml src/main/java/com/example/nacos/dm/ DmDataSourceServiceImpl.java DmDatabaseDialect.java src/main/resources/META-INF/services/ com.alibaba.nacos.plugin.datasource.spi.DataSourceService com.alibaba.nacos.plugin.datasource.spi.DatabaseDialectDmDataSourceServiceImpl的核心逻辑是仿照Nacos默认的ExternalDataSourceServiceImpl把驱动类和连接地址改成达梦的。package com.example.nacos.dm; import com.alibaba.nacos.plugin.datasource.spi.DataSourceService; import com.zaxxer.hikari.HikariDataSource; import javax.sql.DataSource; import java.util.Properties; public class DmDataSourceServiceImpl implements DataSourceService { private HikariDataSource dataSource; Override public DataSource getDataSource() throws Exception { if (dataSource null) { Properties props loadProperties(); String url props.getProperty(db.url.0); String user props.getProperty(db.user.0); String password props.getProperty(db.password.0); dataSource new HikariDataSource(); dataSource.setDriverClassName(dm.jdbc.driver.DmDriver); dataSource.setJdbcUrl(url); dataSource.setUsername(user); dataSource.setPassword(password); dataSource.setMaximumPoolSize(20); dataSource.setMinimumIdle(2); } return dataSource; } private Properties loadProperties() { // 读取conf/application.properties中的db.url.0、db.user.0等配置 return new Properties(); } }这里要注意Nacos主程序里已经有了一套读取application.properties中数据库配置的逻辑loadProperties()的具体实现可以直接参考2.x/3.x源码里ExternalDataSourceServiceImpl的写法或者更简单一点直接在getDataSource()方法里硬编码从System.getProperty读取配置。生产上建议还是走配置文件别硬编码。DmDatabaseDialect的实现更简单如果你的达梦兼容模式足够好可以直接继承MySQL方言package com.example.nacos.dm; import com.alibaba.nacos.plugin.datasource.spi.DatabaseDialect; public class DmDatabaseDialect extends MySqlDatabaseDialect { Override public String getDatabase() { return dm; } }继承MySQL方言有一个前提达梦的MySQL兼容模式支持LIMIT分页。我在DM8上实测过它支持但不同小版本可能存在差异。稳妥的做法是先手动执行一下SELECT * FROM config_info LIMIT 0, 10;如果这条SQL能跑通方言层就直接复用MySQL的分页逻辑如果报错再用ROWNUM改成分页逻辑。这个验证很重要因为Nacos配置列表查询、历史配置查询都重度依赖分页分页挂了控制台基本就瘫了。4.3 打包、部署与3.1.0关键配置项插件写好后用Maven打包成nacos-dm-datasource-plugin.jar然后将jar包放入Nacos 3.1.0安装目录下的插件目录。不同发行版的插件目录名可能略有差异有的叫plugins有的叫plugin也有的是plugins/datasource。以你下载的3.1.0解压后的实际目录为准找不到就全局搜索一下nacos-datasource-plugin相关的目录名。为了让插件里的DmDriver能被正常加载驱动依赖要么打成fat-jar塞进插件包要么单独把达梦JDBC驱动jar放到Nacos的lib目录下。我建议打成fat-jar这样插件分发时不需要额外告诉别人还要放一个驱动jar。然后在conf/application.properties里配置spring.datasource.platformdm nacos.datasource.platformdm db.num1 db.url.0jdbc:dm://127.0.0.1:5236/NACOS db.user.0nacos db.password.0Nacos123这里需要特别提醒一点spring.datasource.platform和nacos.datasource.platform这两个配置项在不同版本里的识别优先级和行为不完全一致。3.1.0里建议两个都写上值都为dm。我在测试中遇到过只写其中一个时Nacos仍然尝试加载默认MySQL分支的情况报错信息是找不到com.mysql.cj.jdbc.Driver排查了好久才反应过来是平台配置没生效。5. 启动验证与配置中心核心回归用例5.1 启动日志怎么排查配置完成后启动Nacos不要急着打开控制台。先盯着启动日志看几行关键信息有没有Failed to create datasource、Cannot load driver class: dm.jdbc.driver.DmDriver这类异常。有没有com.mysql.cj.jdbc.Driver相关的ClassNotFoundException。如果出现这个多半是SPI没生效Nacos还在用默认的MySQL实现立刻检查插件jar是否被正确扫描到、nacos.datasource.platform是否配置成功。日志末尾出现类似Nacos started successfully的输出说明启动阶段没问题。启动阶段不出错只是第一关。真正判断数据源有没有接上可以打开控制台进入配置管理页面如果能正常分页展示已经导入的配置数据说明数据源基本可用。5.2 配置中心的核心功能回归表适配数据库后的回归测试我建议按下面这个表格过一遍每一项都不能跳过功能模块测试步骤预期结果登录认证使用初始账号nacos/nacos登录控制台登录成功进入主页面命名空间管理新建一个命名空间再删除创建和删除均成功配置发布新建dataId为demo.properties的配置内容包含中文和特殊字符发布成功内容完整显示配置查询在配置列表按dataId和group搜索搜索结果准确动态刷新启动一个Spring Cloud应用接入该Nacos修改配置并发布客户端日志收到变更通知本地属性刷新历史版本连续修改同一配置3次进入历史版本列表能看到3个历史版本可回滚到指定版本用户权限新建一个用户授予只读角色该用户能查看配置但不能编辑重启持久化重启Nacos服务端再次查询配置配置数据仍然存在集群节点如果有集群环境查看节点列表节点状态正常动态刷新这条要特别强调一下不要只在控制台里改了配置就算测过。真实的客户端订阅需要通过Nacos客户端或Spring Cloud Alibaba应用来验证。我在适配测试时遇到一个情况控制台配置发布正常、数据库里数据也更新了但客户端一直拿不到新值最后发现是客户端连接的还是旧节点重启客户端重连后才恢复。这种问题跟数据库适配本身无关但很容易让人误判成适配有问题。5.3 服务注册发现为什么会“没压力”前面说过服务发现的数据主要走内存和Raft协议不依赖外部数据库。回归时只需要启动一个服务提供方和一个服务消费方确认注册、心跳、发现、下线这几个基本动作正常即可。不用像配置中心那样做大量数据库相关的场景测试这块的压力主要在Nacos节点之间的Raft通信上跟达梦没什么关系。6. 适配过程中踩过的坑与升级兼容考虑6.1 三个必踩的坑驱动、大小写、字段长度第一个坑是驱动类找不到。插件包虽然写好了但Nacos启动时如果抛ClassNotFoundException: dm.jdbc.driver.DmDriver说明驱动jar没有被插件类加载器看到。解决办法就是把达梦JDBC驱动jar一并打进插件fat-jar里不要指望Nacos主程序会主动加载插件目录下所有的jar。第二个坑是“表或视图不存在”。这个坑最容易让人崩溃因为明明建表成功了SQL看着也没问题但一启动就报错查不到表。根因基本出在达梦的大小写敏感配置上。达梦默认在建库时有一个大小写敏感开关如果开启Nacos生成的SQL里不带双引号的标识符会被达梦自动转成大写而你的建表脚本如果用了小写表名自然就找不到。解决方式是在初始化达梦实例时关闭大小写敏感或者所有表名、字段名统一用大写建表和查询。第三个坑是中文内容写入报“字符串长度超出限制”。达梦的VARCHAR类型默认按字节计算长度一个中文字符可能占3个字节甚至更多。Nacos脚本里如果部分字段仍然用了VARCHAR比如c_desc、c_use这些在写入中文描述时有可能因为长度不够而报错。稳妥做法是凡是可能存中文的字段长度直接放大一倍或者干脆改用CLOB。尤其是content、c_schema、encrypted_data_key这几个字段我全部改成了CLOB一次性能解决所有长度问题。6.2 从2.x升级到3.1.0时容易被忽视的改动如果你手头已经有一套跑在Nacos 2.x上的MySQL库想直接切到3.1.0达梦有几个点需要特别注意。第一是表结构差异。3.x相比2.x多了config_info_gray表这是灰度配置功能的核心表。直接从旧库迁数据时别只导数据不建表否则控制台打开灰度配置相关页面会报错。建议先通过conf目录下的升级脚本确认需要补充哪些表再手工把这部分建表SQL改造成达梦语法执行。第二是SPI接口的包名和类名可能变化。Nacos 2.x时代编译好的达梦插件放到3.1.0下不一定能直接运行。3.x对插件模块做了重构接口签名、包名、依赖版本都可能有调整。如果启动时报NoSuchMethodError或ClassCastException基本就是插件版本不匹配需要用3.1.0对应的源码重新编译。第三是配置项名称的变化。2.x时期老教程里喜欢用spring.datasource.platform3.x里可能改成nacos.datasource.platform才生效。建议升级后立刻检查启动日志确认实际加载的数据源平台确实是dm而不是默认的MySQL或Derby避免表面上连接成功、实际所有数据都写进了内嵌Derby的尴尬情况。6.3 我的几条装机建议这套适配做完之后我自己沉淀了几个习惯也算是一点经验之谈。拿到新版Nacos先别急着启动第一件事是拉出mysql-schema.sql把表结构和目标数据库实际结构对一遍。脚本迁移这种活儿一次性全自动跑通是运气多数情况都需要手工微调慢就是快。任何数据库适配都优先走SPI插件而不是改源码。哪怕只是为了临时验证一个特性也不要在Nacos主程序上动刀否则版本升级时会非常被动。动态刷新的回归一定要有真实的客户端订阅不能只看控制台。配置中心的核心价值就是“改一处、到处生效”如果客户端拿不到变更通知数据库适配得再完美对业务来说也等于没适配。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询