RuoYi适配达梦数据库实战:从SQL兼容到部署全解析
2026/9/16 7:13:35 网站建设 项目流程

1. 为什么要专门写达梦数据库适配这件事

先交代一下背景。我手上维护的那套基于RuoYi的管理系统,跑了将近两年,业务方突然提了个要求:新项目必须跑到达梦数据库上。原因不复杂,信创国产化替代,数据库层不能继续用MySQL了。当时听到这个需求,第一反应是"改个数据源不就完了",但真正动手之后才发现,RuoYi适配达梦不是换个驱动、改个连接串那么简单——如果不做代码层面的调整,项目别说启动,光是启动过程中的表结构初始化、数据字典插入就能挂给你看。

这篇文章是在前面完成基础适配的基础上写的。上一篇讲的是怎么把达梦的JDBC驱动接进去、怎么配数据源、怎么让RuoYi的Spring Boot工程在达梦上把Application跑起来。这一篇重点放在另外几块非常容易踩坑的地方:数据库端的连接管理工具、备份还原操作、系统函数兼容性改造、还有部署到Linux服务器之后偶尔会遇到的一些怪问题。

先说结论:达梦数据库和MySQL之间的差距,用一句话概括就是"鸟和鱼的差距"——它们都有翅膀(SQL标准)、都会游泳(事务、索引、视图),但实现细节完全不同。RuoYi原本是深度面向MySQL写的,比如它的分页插件、主键生成策略、逻辑删除字段、日期格式化函数,还有那张system_menu里的perms字段拼接方式,全都带着MySQL的烙印。直接把这些东西搬到达梦上,就像把一整套南方人的生活习惯照搬到北方,不是不能活,是处处别扭。

我整理了一下我实际遇到过的三大类问题,你可以对照自己手头的项目情况来排查:

问题类型典型表现影响程度
数据库工具链问题Navicat连不上达梦、DBeaver看不到对象导航、DM管理工具界面空白低,影响开发效率
SQL语法与函数兼容Date_FORMAT报错、字符串截取行为不一致、分页语法不兼容高,会导致查询直接失败
框架代码硬编码建表语句里的注释写法、逻辑删除的默认值、序列的使用方式高,影响整套系统初始化

下面每一项我都会详细展开,把操作步骤、遇到的报错、排查链路、最终方案全部讲清楚。

2. 数据源配置调通之后,我建议你先做好这三件事

2.1 检查驱动版本和方言配置

我上一篇文章里已经写了如何在RuoYi工程的pom.xml里引入达梦JDBC驱动,这里只强调一个很多人容易忽略的点:达梦的驱动包版本必须和数据库服务器的版本保持兼容,最好是相同版本。我用的是DM8,驱动是达梦官网下载的DmJdbcDriver18.jar,对应的数据库版本是DM Database Server 64 V8

然后是MyBatis分页方言的问题。RuoYi用的是PageHelper,它内置了对达梦的支持,自动化方言检测能识别出dm关键字。不过有一个前置条件:JDBC URL里的driverClassName必须写对,否则PageHelper识别不了数据库类型,会默认走MySQL方言,然后分页SQL直接语法报错。

正确的配置参考如下:

spring.datasource.druid.driver-class-name=dm.jdbc.driver.DmDriver spring.datasource.druid.url=jdbc:dm://192.168.1.100:5236?schema=RUOYI spring.datasource.druid.username=SYSDBA spring.datasource.druid.password=SYSDBA

这里有个容易踩的坑:达梦的Schema隔离和MySQL的Database隔离完全不是一个概念。MySQL里一个连接指定了database,表就直接在库里;达梦里一个用户对应一个Schema,建表如果不指定Schema,默认创建在登录用户自己的Schema下。所以URL里我加了?schema=RUOYI,意思是连接建立后默认把RUOYI这个Schema设为当前模式。如果你不加这个参数,查询的时候可能会出现"无效的表名"这类问题,因为表虽然在RUOYI模式里,但当前会话默认找不到它。

2.2 建表语句和初始化数据要注意的点

RuoYi自带的sql/ry_2024xxxx.sql是MySQL版本,里面的建表语句用了一堆MySQL专属语法。比如:

  • 字段注释用COMMENT 'xxx'
  • 引擎默认是ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
  • 部分字段用了ON UPDATE CURRENT_TIMESTAMP

达梦对这三种处理方式都不完全兼容。我在上一篇文章的适配包里重新写了一套达梦版本的建表脚本,这里把关键差异列出来:

MySQL写法达梦适配写法
COMMENT '用户ID'COMMENT ON COLUMN 表名.列名 IS '用户ID'单独执行
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4建表语句去掉这行即可
datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPTIMESTAMP DEFAULT CURRENT_TIMESTAMP,更新时间的维护交给应用层代码

尤其注意第二点。如果不加处理直接执行MySQL版本的建表SQL,达梦会报一个语法错误,而且这个错误在DBeaver里看还不太直观,提示的是语法分析出错,特别容易让人误以为是SQL语句本身不完整。当时我是把SQL一条条拆出来,定位到出错的语句之后才反应过来是引擎和字符集声明不兼容。

2.3 主键生成策略必须改

RuoYi里有很多表的主键是自增ID,比如sys_user表的user_idAUTO_INCREMENT。MySQL里直接在表定义里写AUTO_INCREMENT就行,但达梦里不支持这种写法,建表的时候你可以在字段定义上接IDENTITY(1,1),表示从1开始每次递增1。这是一个合法的达梦自增列写法。

但是如果你的表已经建好了,又不能用ALTER语句往已有列上追加IDENTITY属性,那就只能重建表。比较快的方式是:

CREATE TABLE RUOYI.SYS_USER_NEW ( USER_ID INT IDENTITY(1,1), ... ); INSERT INTO RUOYI.SYS_USER_NEW (除USER_ID外所有字段) SELECT 除USER_ID外所有字段 FROM RUOYI.SYS_USER; DROP TABLE RUOYI.SYS_USER; ALTER TABLE RUOYI.SYS_USER_NEW RENAME TO SYS_USER;

另一个方案是改RuoYi的代码,把useGeneratedKeys相关的自增逻辑改成查询序列的下一个值。达梦支持序列,你可以先创建序列,再在插入语句里用NEXT VALUE FOR 序列名。如果不是对性能敏感,我更推荐第一种,改造成本低很多。

3. 连接管理工具:一个都不能少,但每个都要踩一遍坑

3.1 Navicat连接达梦的两种方式

Navicat从16.x版本开始原生支持达梦数据库,不需要额外插件。连接的时候数据库类型选"达梦数据库",主机填达梦服务器的IP,端口默认是5236,用户名密码用数据库里的真实用户就行。连好之后左侧对象树里能看到模式、表、视图、存储过程这些。

但有一个情况要注意:如果你用的是旧版Navicat,或者公司正版授权不允许随便升级,那么需要去达梦官网下载达梦自带的JDBC驱动,然后通过Navicat的"管理连接"->"高级"里加载驱动。这种方式成功率不高,我不太推荐,最好还是直接用达梦官方的DM管理工具,或者升级Navicat。

3.2 DM管理工具没有对象导航栏

这个问题我搜索的时候看到网上很多人问,我实际也遇到过。达梦的DM管理工具(也就是达梦自带的图形化客户端)打开之后,左侧导航栏如果一片空白,看不到任何模式或表,通常是下面几个原因之一:

  1. 当前登录用户权限不足,只能看到自己的模式,如果"显示系统对象"没勾选,看起来就像没有对象。
  2. 连接时选择的Schema不正确,导致目标模式中没有对象。
  3. 客户端版本与服务器版本不匹配,偶发元数据加载失败。

我的解决办法比较直接:在DM管理工具里用SYSDBA登录,然后在工具栏里找到"选项"->"显示"->勾选"显示系统对象"和"显示所有模式"。如果是普通业务用户,就在登录界面把Schema切到对应用户下,实在不行就换DBeaver连上去看。

3.3 DBeaver连接达梦的详细配置

DBeaver是很多人日常用的免费开源数据库客户端,它对达梦的支持不算开箱即用,但配置很简单。DBeaver编辑连接时,数据库类型里如果没有"达梦数据库",需要手动添加驱动。

驱动配置信息如下:

  • 驱动名称:任意,比如DM JDBC Driver
  • 驱动类型:Generic
  • 类名:dm.jdbc.driver.DmDriver
  • URL模板:jdbc:dm://{host}:{port}
  • 默认端口:5236

添加完驱动后,把达梦JDBC的jar包加到驱动库里,然后在连接信息里填上主机、端口、用户名、密码。连接成功后,左侧导航栏同样需要手动刷新才能显示Schema。如果刷新后还是空白,可以右键连接选"连接设置",在"驱动属性"里加上schema=RUOYI,让它打开连接时自动定位到目标模式。

DBeaver有个比DM管理工具好用的点:SQL编辑器里写查询语句时,字段提示和表提示都做得比较完整,写复杂SQL的时候效率高不少。

3.4 突然连不上数据库的排查套路

有一段时间我这边开发环境时不时出现"连接被拒绝"的报错,一开始以为是网络问题,后来发现不是。整理一下出现这个问题的常见排查路径,按顺序检查:

  1. 先确认服务进程还活着。Linux上用systemctl status DmServiceDMSERVER查看,Windows上在服务管理里看DmService状态。
  2. 再确认端口在监听。Linux执行netstat -anp | grep 5236,Windows执行netstat -ano | findstr 5236
  3. 如果服务正常、端口在监听,但还是连不上,就要看是不是连接数满了。达梦默认最大会话数有限,我当时的开发库被好几个同事共用,连接数一满,新连接就进不来。
  4. 登录达梦管理工具,执行SELECT COUNT(*) FROM V$SESSIONS;,如果接近上限,那就需要调大参数,或者让闲置连接释放。

关于会话数,曾经还遇到过一个有意思的问题:达梦数据库提示"未设置会话超时时间"。这个意思是服务端没有做空闲连接超时回收,导致一堆无效连接常年占着会话。解决办法是在达梦的dm.ini里设置会话超时参数,比如把SESS_TIMEOUT设为600秒。改完之后重启数据库服务生效。

4. SQL函数与语法适配:这是改造量最大的一块

4.1 日期函数不通用

RuoYi里有不少查询会用到MySQL的DATE_FORMAT函数,比如字典数据查询时格式化创建时间。达梦支持DATE_FORMAT吗?答案是看版本。DM8早期版本不认这个函数,如果你直接用原生SQL调用,会报"无效的函数名"之类的错。

我当时的做法是全局搜代码,把涉及DATE_FORMAT的地方替换成两个等价的达梦写法:

-- 原MySQL写法 SELECT DATE_FORMAT(create_time, '%Y-%m-%d %H:%i:%s') FROM sys_user; -- 达梦写法一 SELECT TO_CHAR(create_time, 'YYYY-MM-DD HH24:MI:SS') FROM sys_user; -- 达梦写法二 SELECT TO_DATE(create_time, 'YYYY-MM-DD HH24:MI:SS') FROM sys_user;

第二种写法里如果create_time本身就是TIMESTAMP类型,那直接用TO_CHAR转换就可以了。问题是RuoYi里有些Mapper XML的查询语句里的DATE_FORMAT是被包裹在<if>标签里的,只改SQL还不行,得把动态SQL里的判断条件一起调整。

比如原先的判断可能是if test="params.beginTime != null and params.beginTime != ''",然后把beginTime拼进DATE_FORMAT函数里。改造之后要保留这个判断,但里面的SQL片段换成TO_CHAR。这种细节很多,不改的话单查语法过了,数据一多运行时就报错。

4.2 分页查询的确定性

PageHelper在达梦上能正常工作,但有个细节需要注意:达梦的分页语法有两种写法,一种是LIMIT OFFSET,一种是TOP N配合子查询。PageHelper使用的是前者,也就是它生成的SQL会像这样:

SELECT * FROM sys_user LIMIT 10 OFFSET 20;

这种语法在DM8里是支持的。我之前遇到过的分页问题不是语法本身,而是PageHelper的方言识别失败,导致生成的SQL还是MySQL方言。排查方法是在配置文件里显式指定:

pagehelper.helper-dialect=dm pagehelper.reasonable=false

显式指定之后,分页就正常了。这里强调一个经验:依赖自动检测不是一个好习惯,尤其是从MySQL切到达梦这种跨数据库迁移的场合,显式配置能省掉大量排查时间。

4.3 字符串函数和隐式转换的坑

达梦对字符串和数字混用时,隐式转换规则和MySQL不完全一样。举个真实例子:

我有一张业务表,主键字段定义成VARCHAR(32),存的值是雪花算法生成的纯数字ID。RuoYi前端传参时把ID序列化成字符串,这个没问题,但MyBatis的XML里如果把ID和另一个字段做比较时写得不严谨,比如:

WHERE user_id = #{userId}

userId是Integer类型,而user_id是VARCHAR时,MySQL会先把VARCHAR转成数字再比较,达梦在某些模式下会报"数据类型不匹配"的错。

解决办法要么是保证参数类型和字段类型一致,要么在SQL里加TO_CHAR(user_id) = #{userId}。但这样会导致索引失效,所以最佳方案还是让代码里所有传参都统一成String。我在适配过程中专门写了一个MyBatis的类型处理器,把所有主键参数统一转String,彻底绕开了这个问题。

另外,字符串截取函数也必须改。MySQL的SUBSTRING(str, pos)从1开始计,达梦的SUBSTRING也是从1开始计,这个还好。真正容易出错的是GROUP_CONCAT,MySQL常用它做行转列拼接,但达梦没有同名函数,需要用LISTAGG代替。

RuoYi里面有一个生成字典数据的功能,会用到类似行转列的操作,当时改造的时候就把GROUP_CONCAT换成了LISTAGG,语法如下:

-- MySQL SELECT GROUP_CONCAT(dict_label SEPARATOR ',') FROM sys_dict_data WHERE dict_type = 'xxx'; -- 达梦 SELECT LISTAGG(dict_label, ',') WITHIN GROUP (ORDER BY dict_sort) FROM sys_dict_data WHERE dict_type = 'xxx';

注意LISTAGG的语法里必须带WITHIN GROUP和排序条件,否则达梦会直接报错。这个函数差异是RuoYi适配达梦里最容易被忽视的坑之一。

5. 达梦数据库的常用维护操作:备份、还原、导入DMP

5.1 Windows和Linux上的备份方式

备份这块儿我强烈建议直接用达梦自带的DMRMAN工具,或者用DM管理工具的图形化界面。命令行备份的格式如下:

dmrman CTRLFILE=/dm/data/DAMENG/dm.ctl BACKUP DATABASE '/dm/data/DAMENG/DAMENG' FULL BACKUPSET '/backup/full_bak_2024_01_01';

Linux上执行前需要先切换到dmdba用户,否则文件权限会出问题。Windows上的命令行类似,只是路径写法不同。如果是在DM管理工具里备份,右键数据库名选"备份",然后指定备份集路径和备份方式(全量或增量)就行。

对RuoYi这类系统来说,数据库里存的主要是组织、用户、角色、菜单这些基础数据和业务表数据,备份策略建议每天全备一次,重要变更前再手动备份一次。我见过有人把备份文件直接放在数据库服务器的安装目录下,这种做法不太建议,最好挂载独立的磁盘或备份目录,免得数据库数据盘满了连带系统出问题。

5.2 还原DMP文件的两种方法

达梦的DMP文件从哪来?最常见的是两个渠道:一是从达梦的dexp逻辑导出工具导出的,二是从其他迁移工具生成的。还原方式有两种:

第一种,用DM管理工具图形化操作。左侧对象导航里选中"数据库实例" -> 右键选择"还原" -> 选择DMP文件,按向导下一步就行。这个方法比较直观,适合数据量不大的场景。

第二种,用命令行工具dimp。命令示例:

dimp SYSDBA/SYSDBA@localhost:5236 FILE=/backup/test.dmp FULL=Y DIRECTORY=/backup

参数说明:

  • SYSDBA/SYSDBA是用户名和密码
  • FILE指定DMP文件路径
  • FULL=Y表示整库导入
  • DIRECTORY是辅助文件所在目录,建议和DMP文件放同一个目录

我在实际还原过程中遇到过一个问题:DMP文件是用旧版本达梦导出,现在导入到新版本,报了一些对象无效的警告,尤其是存储过程、视图这类对象。这种情况下不用太慌,因为大都是依赖了某个不存在的表或者字段,检查一下目标库的表结构是否完整、是不是缺少某些依赖表,问题基本都能定位。

5.3 关于还原时提示“对象已存在”的处理

如果你是在已经有用户和Schema的库里执行还原,尤其当库是用别的方式初始化过一遍的时候,经常会出现"对象已存在"的报错。这个报错本质是达梦的元数据里已经存在同名的表、序列或约束,而dimp默认不会覆盖,它直接跳过或者报错。

解决办法有两个思路:

  1. 在导入之前先删掉目标用户下的所有对象(前提是确认可以清空)。
  2. 使用dimp时加TABLE_EXISTS_ACTION=REPLACE参数,让它在遇到已有表时先删后建。

但第二种方式有风险:如果目标表里有业务数据,加这个参数等于强制覆盖,数据会丢。所以我个人习惯是先完整备份一次,再决定要不要用这个参数。整个还原流程我用一个表格整理一下:

步骤操作内容注意事项
1备份当前库全量备份,防止误操作
2确认DMP文件来源确认是逻辑导出还是物理备份
3检查目标用户权限必须有DBA权限或对应对象权限
4执行还原小库用DM管理工具,大库用dimp命令行
5核对日志重点看报错对象列表
6验证数据抽查业务表记录数、关键视图查询

6. 达梦的常用函数和脚本:首拼码函数怎么生成

6.1 需求来源

开发系统时,很多场景需要根据汉字名称生成拼音首字母串,比如客户表里有个"客户简称"字段,希望在输入中文名称时自动生成一个首字母编码用于搜索或去重。既然是在达梦数据库上,业内最标准的做法就是写一个达梦的存储函数,叫做"生成首拼码函数"。

6.2 达梦的汉字转拼音方案

达梦内置了对汉字转拼音的底层支持,但不像Oracle那样有可以直接调用的函数包。要生成首拼码,需要自己写函数,利用达梦的字符函数NLSSORT或者通过编码对照表。网上流传比较广的做法是建一张拼音首字母对照表,然后把每个汉字的UNICODE编码区间映射成字母。

我采用的做法是参考达梦官方社区的一个存储函数实现。函数核心逻辑是把汉字按Unicode编码范围分段映射到A-Z。因为常用汉字的Unicode范围比较集中,这个方案准确率高,覆盖常用汉字足够。

示例函数结构如下:

CREATE OR REPLACE FUNCTION GET_PY_JM(STR IN VARCHAR2) RETURN VARCHAR2 IS RESULT VARCHAR2(1000); BEGIN RESULT := ''; FOR I IN 1..LENGTH(STR) LOOP -- 取单个字符的Unicode编码 -- 根据编码区间映射到A-Z -- 拼接到RESULT END LOOP; RETURN RESULT; END;

这个函数在DM8里编译运行没问题。生成之后,你可以建一个触发器或者直接在应用层插入时调用。我的建议是不要在每一条SQL里实时调用这个函数,因为性能一般,最好是在写入的时候把首拼码字段直接算好存到表里,查询的时候直接查这个字段,速度最快。

6.3 达梦函数使用的小贴士

在达梦里写自定义函数,有几点和MySQL很不一样,适配人员容易踩坑:

  1. 函数参数如果没有指定模式,默认是IN类型,这个可以接受。
  2. 函数体内部不能用MySQL的IF语法,必须用达梦的IF-THEN-ELSECASE分支。
  3. 字符串拼接不能用+,必须用||
  4. RETURN后面接的是返回值表达式,不是变量名列表,别和存储过程的输出参数搞混。

这些细节在写的时候很容易出问题,但一旦绕过这两步,函数本身的逻辑就能写得和MySQL版几乎一致。

7. Linux服务器上的部署与连接问题排查

7.1 在华为欧拉系统上安装达梦数据库

现在很多项目要求国产化硬件和国产化系统,华为欧拉就是其中比较常用的Linux发行版。达梦数据库官方对欧拉是有适配包的,安装过程本质上就是把解压后得到的安装目录放到合适的位置,然后运行DMInstall.bin,按向导操作。

我在欧拉上装过一次,遇到了几个小问题,列出来供参考:

  1. 需要提前创建dmdba用户,不然安装程序会用root用户跑,数据库服务后继权限管理很麻烦。
  2. 安装目录的权限必须给到dmdba用户,不然初始化实例的时候会报权限错误。
  3. 欧拉系统如果没装图形化界面,用命令行安装模式,先执行./DMInstall.bin -i,然后按提示选择语言、安装路径、是否初始化实例。
  4. 初始化实例时要注意指定字符集和页大小,达梦安装完成后不好改,最好一开始就选对。

7.2 Docker容器里的应用怎么连到达梦

有一种部署方式很常见:应用本身容器化,数据库放在宿主机或者另一个容器里。我在做RuoYi容器化改造时遇到的连接问题,基本都是网络层面导致的。

最常见的问题:RuoYi容器内通过localhost:5236连接达梦,但达梦跑在宿主机上,容器里的localhost指向的不是宿主机。正确的写法是把数据库地址配成宿主机在Docker桥接网络里的IP,或者在启动容器时用--network=host,直接让容器共享宿主机网络。

如果你用的是Docker Compose编排,可以让应用服务和达梦数据库服务在同一个网络里,互相用服务名访问,比如数据库服务名是dameng,那RuoYi连接时就用jdbc:dm://dameng:5236,前提是容器网络没问题。

7.3 Java服务器连达梦时的常见异常

RuoYi部署到Linux服务器后,日志里出现一些奇怪的连接异常是很正常的,关键是看异常类型。我整理几个高频异常:

异常信息可能原因解决思路
连接超时防火墙拦截5236端口开放端口或在达梦主机上放行
无效的授权达梦数据库License过期检查License有效期,联系商务续期
创建连接失败连接池参数不当检查Druid的initialSize和maxActive配置
无效的表名Schema未指定在JDBC URL中加schema参数

特别说一下License过期的问题。我遇到过测试环境里达梦数据库突然连不上,各种排查下来,最后发现是License到期。达梦在License到期后不会直接把库关掉,但会拒绝新建连接,所有新的请求都会报"无效的授权"之类错误。这个坑特别隐蔽,因为已经建立的长连接不会断,但你一旦重启应用,就再也连不上了。

所以如果出现"突然连不上"的情况,检查完防火墙、网络、服务状态之后,一定要记得看一下License状态,命令是:

/opt/dmdbms/bin/dmlicense

或者直接在DM管理工具里查看“关于”页签。

7.4 RuoYi任务不执行的问题排查

接到过一个问题:RuoYi里的定时任务不执行了。原本在MySQL上跑得好好的,适配达梦之后,定时任务界面里能看到任务记录,但到了计划时间就是不触发。

排查链路如下:

  1. 先看RuoYi动态定时任务的实现机制,它把任务配置存到了sys_job表里,由后端轮询表状态来决定是否触发。如果表里的status字段默认值是0(正常),那大概率不是状态问题。
  2. 检查sys_job表里的cron_expression字段。如果任务是通过页面新增的,这个字段应该已经生成。要注意达梦里字段值如果被隐式转换为其他类型,可能导致表达式解析异常。
  3. 查看RuoYi的定时任务线程池日志,看有没有报错。如果jobInvoke方法抛了SQLSyntaxErrorException,那基本可以断定Mapper XML里的SQL语法在达梦上不兼容。
  4. 用console手动执行一次任务,如果手动执行也失败,就去看堆栈里异常信息是哪条SQL。我当时定位到一个任务是用INSERT INTO ... VALUES,里面用了MySQL的自增列占位写法,到达梦上直接报错,改完之后任务就正常了。

定时任务适配这块,本质是看有没有跨数据库的SQL方言,如果确认SQL没问题还是触发不了,再看sys_job_log表有没有对应的日志。日志如果显示任务成功但实际没效果,那就去检查业务SQL里的函数兼容性,比如用了NOW()这种MySQL函数,达梦中应该用CURRENT_TIMESTAMPSYSDATE

8. 几个RuoYi特有功能的达梦适配细节

8.1 菜单权限表sys_menu的字段适配

RuoYi的菜单权限设计用到了sys_menu表,其中perms字段存储权限标识字符串。在MySQL里,这个字段的长度是100,用的字符集是utf8mb4,能存下中文和英文组合的权限字符串。达梦里如果库的字符集设置不对,插入超长或包含特殊字符的字符串时,会出现"字符串截断"或"字符集转换失败"。

适配建议是把这类字段的长度统一放宽到200字符,保证权限字符串不会因为长度不够而截断。同时检查数据库的字符集设置,DM8支持UTF-8,如果初始化实例时用了默认的GBK字符集,那么所有中文字符在应用层可能会乱码,而且乱码问题在JDBC层面特别难查。

8.2 treeselect和表单控件宽度问题

网上有人反馈RuoYi的treeselect下拉框、日期框、输入框宽度不一致,这个问题在达梦适配时其实更容易出现,因为达梦对字段类型映射和MySQL不一样。

如果你在代码生成器里把某张表的字段生成成了和MySQL版本名称一样的字段,但达梦里某些类型被映射成了差异类型,页面上呈现的表单控件就可能出现宽度不统一。这个本质上不是达梦的锅,是因为前端渲染时,每个控件绑定的字段类型影响到了组件的样式判断。

解决办法是在前端样式层面统一控件的类名,给所有控件加一个固定的宽度类,例如:

.el-select, .el-date-editor, .el-input { width: 100%; }

这个改法能一次性解决所有控件宽度不一致的问题,不需要逐个调组件属性。

8.3 集成WebSocket和MQTT时要注意什么

如果你基于RuoYi做物联网类项目,可能需要集成WebSocket和MQTT。WebSocket本身和数据库关系不大,主要是后端Session管理的问题。当RuoYi适配达梦后,如果用了集群模式,WebSocket的Session信息如果要持久化到数据库,那就要注意达梦对字段类型的支持。

MQTT也是一样,很多方案用数据库存储客户端的连接状态、遗嘱消息、会话消息。达梦对JDBC这块的兼容性不错,但要注意消息内容如果很长,VARCHAR字段长度是否够用,建议用CLOB类型存消息体。如果用的是RuoYi自带的通用Mapper,改造时要在实体类里用@Lob注解标识CLOB字段。

8.4 sharding-jdbc和达梦的配合

有网友问到sharding-jdbc-spring-boot-starter和RuoYi结合使用,还要适配达梦。这个组合本身可行,但要注意ShardingJDBC的分页、排序等SQL解析器对达梦的支持情况。ShardingSphere从5.x版本开始增强了对国产数据库的支持,达梦也在兼容范围内。

不过我的建议是:如果业务复杂度没那么高,尽量别用ShardingJDBC去分库分表,因为RuoYi默认没有分库分表的设计,强行引入ShardingJDBC会增加SQL解析的不确定性。如果表数据量确实很大,先考虑用达梦的按分区表方案,这个更稳。

9. 关于改造顺序和风险控制的一点经验

适配达梦是有先后顺序的。我第一次做的时候没有规划,结果前后返工了好几次。最终总结下来的推荐顺序是:

  1. 先搭好环境:安装达梦数据库、建好用户和Schema、初始化RuoYi基础表
  2. 再跑通应用启动:验证驱动、数据源、分页插件、基础CRUD
  3. 接着处理业务模块:从核心模块到边缘模块逐个测试
  4. 最后做特殊功能:定时任务、代码生成器、工作流、MQTT等
  5. 最后才是整体回归和性能调优

这条顺序的逻辑是:基础不牢,上层越做越乱。如果数据源都没完全通,直接去改业务SQL,那么报错时你很难判断是SQL问题还是连接问题。

风险控制方面,我要重点提一个建议——改造过程中,每一步改动都要用Git打好标签,尤其是Mapper XML、配置文件、建表脚本这几类文件。我经历过一次意外:把某个Mapper XML里的DATE_FORMAT全部替换成TO_CHAR之后,回滚时发现连备份都不完整,只能手工恢复。从那以后,所有跨数据库适配的改动我都要求必须有不同的commit,方便随时回滚。

另外,sys_config表里的参数也不容忽视。RuoYi框架会在启动时读取配置,比如sys.index.skinNamesys.user.initPassword这些参数。如果初始化脚本没有把对应键值插进达梦库,应用虽然能启动,但页面上某些功能会表现异常,比如用户管理默认密码不生效、主题皮肤切换失效。

这类问题不好排查,因为它们不报错,只是行为不符合预期。我的建议是初始化之后,用下面这条SQL检查关键配置是否完整:

SELECT CONFIG_KEY, CONFIG_VALUE FROM SYS_CONFIG WHERE CONFIG_KEY LIKE 'sys.%';

对照MySQL环境里的配置值一条条核对,保证没有遗漏。

10. 最后分享几个我在实际项目中用到的习惯

截止到这里,RuoYi适配达梦的主要战场基本都覆盖了。最后写几个完全来自个人实战的小经验,不系统,但管用。

第一个,达梦数据库的日志需要定期清理。DM8的日志文件默认在数据库安装目录下的log文件夹,运行时间长了会变得非常大。我刚接手的时候,运维反馈磁盘空间紧张,查了半天才发现是达梦的日志文件占了将近20G。当时在DM管理工具里开启了自动清理,后来也定时检查,磁盘空间问题再没出现过。

第二个,务必在所有新表和改造后的表上显式创建索引。RuoYi自带脚本里的索引相对克制,适配达梦时如果直接导入老数据,数据量一大,不带索引的查询会非常慢。而达梦的优化器在统计信息不完整时,执行计划可能走全表扫描。建议在完成数据迁移后执行一次:

DBMS_STATS.GATHER_SCHEMA_STATS('RUOYI');

这个命令能刷新整个Schema的统计信息,效果非常明显。我遇到过一条业务报表SQL,在MySQL上3秒出结果,迁移到达梦之后跑了30秒,就是统计信息没更新,达梦选错了执行计划。

第三个,JDBC连接参数里加上escapeProcess=false,这个参数可以让达梦驱动不额外处理转义字符,能避免很多字符串拼接场景下多一个反斜杠或少一个反斜杠的问题。

第四个,RuoYi的代码生成功能生成实体类时,会把表字段类型映射成Java类型。默认的映射规则对达梦不一定友好。比如达梦的DECIMAL类型默认可能有精度,映射成Java的BigDecimal没问题,但如果你在代码生成器里没配置好,容易生成成LongString,后面做数据校验时就麻烦。所以在用代码生成器生成业务模块前,先到达梦里确认每个字段的类型映射。

我也是跑了半年多、踩了几十个坑之后,才把这套流程跑顺。现在再遇到国产数据库适配安排,我不会慌,按步骤来,基本上心里有数。希望这篇文章里记录的这些细节,能帮你少走一些弯路。适配达梦这件事,说难不算难,但真的要细心,数据库方言的每一个差异,都可能在某个深夜变成一条毫无头绪的报错日志。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询