news 2026/9/8 17:24:55

若依框架从MySQL迁移到达梦数据库的完整实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
若依框架从MySQL迁移到达梦数据库的完整实战指南

简介:若依框架与达梦数据库的集成源码包,面向需要在国产化环境下搭建企业级应用的Java后端开发者,解决将若依默认数据源切换到达梦后的适配与配置难题。压缩包共635个文件、4.66MB,以253个Java核心代码、124个HTML页面、83个JS脚本、30个XML配置文件为主,同时含SQL脚本、YML配置及Druid数据源调整相关文件,覆盖后端逻辑、前端页面、数据库初始化与项目配置等关键环节。已有3032人学习下载。读者能从中掌握达梦JDBC驱动引入、数据源参数修改、SQL方言兼容、事务与异常处理、索引及数据库参数调优等实操方法,可直接在信创项目中参考复用,有效缩短国产数据库迁移与对接周期。 最近接到一个比较特殊的改造任务:把若依框架(RuoYi-Vue 前后端分离版)整套从默认的 MySQL 迁到达梦数据库。刚开始我以为这就是改个连接串的事,毕竟大家平时换库基本都是换 driver、改 url、然后祈祷一次过。真动起来才发现,若依对 MySQL 的隐性绑定远不止数据源配置,光 SQL 方言和代码生成器就花了我将近一周的休息时间。这篇文章就把我实际改造的完整源码思路、踩坑经过和可复用的适配方案整理出来,给准备做类似集成的朋友一个参考。

这个方案适合谁?手里有若依源码、但被要求必须跑在达梦数据库上的开发者;正在做国产化适配、需要把 Spring Boot + MyBatis 项目迁到达梦的人;以及那些想搞清楚“若依到底有多少地方绑死 MySQL”的好奇派。下文用的若依版本是 RuoYi-Vue 3.8.x 前后端分离版,数据库是达梦 DM8,JDK 1.8,Spring Boot 2.5 系列,如果你手里的版本和我不同,核心思路照样通用。

1. 迁移前的伏笔:若依对MySQL的绑定到底有多深

先说结论:若依换成达梦,难点不在 Spring Boot,而在 SQL 方言、自增列语法、分页方言、代码生成器四块。这四块任何一个没处理干净,项目都能跑起来,但总会在某个业务页面给你颜色看。

我习惯在动工前先盘点“绑定点”,把风险摸清楚再动手。若依和 MySQL 的绑定关系大概有六处,我列了个表:

绑定位置默认实现迁移影响
数据源配置com.mysql.cj.jdbc.Driver必须替换为达梦驱动,Druid 校验 SQL 也要改
初始化脚本ry_2023.sqlENGINE=InnoDBAUTO_INCREMENT等语法必须改写
Mapper XML大量 MySQL 函数和分页写法IFNULLDATE_FORMATLIMIT等需要兼容处理
PageHelper 分页helper-dialect: mysql要改成 dm 方言,否则分页 SQL 会拼错
代码生成器查询information_schema达梦没有该视图,必须换系统字典表
Quartz 定时任务使用qrtz_系列 SQL达梦安装目录自带 Quartz 建表脚本,可直接替换

这个表的意义在于:它告诉你不止是配置层的问题。很多人改到一半发现“SQL 报错怎么越来越多”,就是因为只改了数据源,后面几个点完全没排进计划。

我的迁移策略是分四条线并行推进:数据库实例准备、依赖与数据源改造、Mapper SQL 转换、代码生成器适配。跑通主流程后再回头处理 Quartz 和细节报错。下面按这个顺序一步步说。

2. 建库建表与依赖置换:先把地基铺对

2.1 达梦实例与用户准备

达梦安装完成后,默认端口是5236,安装路径下有DM管理工具,类似 Navicat 的图形界面。第一次建议直接用管理工具操作,命令行方式等熟练了再用。

在管理工具里执行下面这段 SQL,创建独立用户,避免所有表都堆在 SYSDBA 下面:

CREATE USER RUOYI IDENTIFIED BY "Ruoyi_123"; GRANT DBA TO RUOYI;

这里我直接给了 DBA 权限,图省事方便调试。生产环境建议按最小权限分配,但达梦对普通用户建表、建视图、建序列的限制比 MySQL 细碎很多,权限不足会不断报 “无效的表或视图名”“权限不足”,排查起来很耗时间。先 DBA 跑通流程,再收敛权限,是我一贯的做法。

需要注意一个细节:达梦默认会把不带引号的标识符转成大写存储,所以用户名RUOYI实际存的是大写。后面 JDBC 连接串里如果用schema=RUOYI,大小写必须对应,否则会报无效的模式名

2.2 初始化 SQL 的达梦改写

若依原始 SQL 是纯 MySQL 风格,比如sys_user表开头是这样的:

create table sys_user ( user_id bigint(20) not null auto_increment comment '用户ID', dept_id bigint(20) default null comment '部门ID', user_name varchar(30) not null comment '用户账号', ... primary key (user_id) ) engine=innodb auto_increment=100 comment = '用户信息表';

这段拿到达梦执行,基本一行都过不去。达梦不认auto_increment、不认engine=innodb、不认行内comment。我按达梦语法重写成了:

CREATE TABLE sys_user ( user_id BIGINT IDENTITY(100, 1) NOT NULL, dept_id BIGINT, user_name VARCHAR(30) NOT NULL, nick_name VARCHAR(30) NOT NULL, user_type VARCHAR(2) DEFAULT '00', email VARCHAR(50) DEFAULT '', phonenumber VARCHAR(11) DEFAULT '', sex CHAR(1) DEFAULT '0', avatar VARCHAR(100) DEFAULT '', password VARCHAR(100) DEFAULT '', status CHAR(1) DEFAULT '0', del_flag CHAR(1) DEFAULT '0', login_ip VARCHAR(128) DEFAULT '', login_date DATETIME, create_by VARCHAR(64) DEFAULT '', create_time DATETIME, update_by VARCHAR(64) DEFAULT '', update_time DATETIME, remark VARCHAR(500) DEFAULT '', PRIMARY KEY (user_id) ); COMMENT ON TABLE sys_user IS '用户信息表'; COMMENT ON COLUMN sys_user.user_id IS '用户ID'; COMMENT ON COLUMN sys_user.dept_id IS '部门ID'; -- 后续字段注释类似,不再赘述

自增列这里用了IDENTITY(100, 1),等价于 MySQL 的AUTO_INCREMENT=100,起始值从 100 开始,步长 1。这是达梦最省事的自增方案。若依初始化脚本里几乎所有表都带自增值,记得统一处理。

如果嫌一个个改COMMENT ON麻烦,也可以写个正则批量替换,把行尾comment 'xxx'摘出来生成COMMENT ON语句。我当时是手工加了前几张表,后面几十张表用脚本生成的,不推荐纯手工,容易漏。

2.3 pom 依赖与驱动来源

若依默认的ruoyi-admin模块里引了mysql-connector-java,要换掉。把 MySQL 驱动从 pom 中剔除,替换成达梦驱动:

<dependency> <groupId>com.dameng</groupId> <artifactId>DmJdbcDriver18</artifactId> <version>8.1.3.62</version> <scope>system</scope> <systemPath>${project.basedir}/lib/DmJdbcDriver18.jar</systemPath> </dependency>

为什么用systemscope 而不是普通依赖?因为达梦的 JDBC 驱动不会默认发布到 Maven 中央仓库,很多内网环境根本拉不到这个包。把DmJdbcDriver18.jar直接从达梦安装目录(一般在%DM_HOME%/drivers/jdbc/下)拷贝到项目lib目录,再用systemPath引入,是我验证过最不容易出问题的方式。

如果你不愿意在 pom 里写死路径,更规范的做法是先用命令手动装进本地仓库:

mvn install:install-file -Dfile=DmJdbcDriver18.jar -DgroupId=com.dameng -DartifactId=DmJdbcDriver18 -Dversion=8.1.3.62 -Dpackaging=jar

装完后再用普通依赖坐标引用。两种方案都能跑,但 systemPath 对团队协作更友好——同事拉代码后不用先执行 install 命令。

还要提醒一点:DmJdbcDriver18 对应 JDK 1.8+,若依默认就是 JDK 1.8,没问题。如果你项目里是 JDK 7 的老环境,得换 DmJdbcDriver17,别搞混。依赖置换完成后处理 druid 连接池和 pagehelper 配置,这个放到第 4 节专门讲。

3. Mapper SQL方言转换:从sys_user到quartz表的逐段排查

3.1 字段类型和建表语法对照

这一节是工作量的大头。若依所有核心表都在ry_2023.sql这类初始化脚本里,我转完后发现,真正需要改的字段类型其实不多,因为达梦对 MySQL 常见类型的兼容度比预料中高。

MySQL 类型达梦建议写法说明
bigint(20)BIGINT长度标识可去掉,达梦不强制
int(11)INT同上
varchar(30)VARCHAR(30)完全兼容
datetimeDATETIME达梦支持,也可用TIMESTAMP
tinyint(1)TINYINT兼容,但代码里可能转 Boolean,需留意
textTEXTCLOB建议直接上CLOB,兼容性最好
longtextCLOB若依里gen_table的建表语句常用 longtext,必须改

真正麻烦的是 MySQL 的行内COMMENT语法,以及带索引前缀长度的写法。MySQL 里允许KEY idx_user_name (user_name(20))这种前缀索引,达梦不支持,必须去掉括号里的长度,直接建普通索引:

CREATE INDEX idx_user_name ON sys_user(user_name);

3.2 Mapper XML 中常见函数替换

若依的 Mapper XML 里藏着不少 MySQL 函数,跑起来后报错会一个接一个。我整理了一份高频替换表:

MySQL 写法达梦兼容写法出现位置举例
IFNULL(a, b)NVL(a, b)COALESCE(a, b)各种列表查询的默认值
DATE_FORMAT(t, '%Y-%m-%d')TO_CHAR(t, 'YYYY-MM-DD')导出、统计类 SQL
GROUP_CONCAT(x)LISTAGG(x, ',')代码生成器字典查询
NOW()/SYSDATE()SYSDATE插入和更新时间
LIMIT a, bOFFSET a ROWS FETCH NEXT b ROWS ONLY尽量不要手写,交给 PageHelper

这里我想展开说一下。很多朋友一看到LIMIT报错就冲进 Mapper 里改 SQL,方向错了。若依的分页功能统一走 PageHelper,startPage()会自动拦截 SQL 并追加方言,所以最优先做的是把pagehelper.helper-dialect配置成dm。只有那些 Mapper XML 里手动写了LIMIT 1的场景才需要人工处理。

比如若依里某个查询后端逻辑需要取一条数据,原始 MySQL 是:

<select id="selectConfigByKey" resultMap="SysConfigResult"> select * from sys_config where config_key = #{configKey} limit 1 </select>

这种要看运气,达梦部分版本兼容LIMIT 1,但为了稳,我会改成等价的达梦写法:

<select id="selectConfigByKey" resultMap="SysConfigResult"> select * from sys_config where config_key = #{configKey} fetch first 1 rows only </select>

FETCH FIRST 1 ROWS ONLY是 SQL 标准写法,达梦完全支持,也不会和 PageHelper 的分页逻辑冲突。

3.3 Quartz 定时任务表

若依自带 Quartz 定时任务,启动时要求qrtz_开头的一堆表存在。MySQL 版本的建表脚本同样不能直接用。

达梦安装目录下其实自带了 Quartz 建表脚本,路径一般在:

%DM_HOME%/dmdbms/samples/quartz/quartz_DM.sql

直接用这个脚本建表最省心,省得手工改LONG VARCHARBLOB这些类型。若依的 Quartz 逻辑本身不涉及数据库方言,表一建,任务调度就能跑。如果找不到这个脚本,也可以把 MySQL 脚本里的engine=innodbcomment全删掉,varbinaryVARBINARYBLOB,手工处理也能过。

4. 数据源与分页插件配置:让Druid和PageHelper认识达梦

4.1 application-druid.yml 改造

若依的数据源配置文件是application-druid.yml,默认指向 MySQL。我改造后的核心片段如下:

spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName: dm.jdbc.driver.DmDriver druid: url: jdbc:dm://127.0.0.1:5236?schema=RUOYI username: ruoyi password: Ruoyi_123 # 初始连接数 initial-size: 5 # 最小空闲连接数 min-idle: 5 # 最大连接数 max-active: 20 # 获取连接等待超时时间 max-wait: 60000 # 校验 SQL,达梦建议用 DUAL validation-query: SELECT 1 FROM DUAL test-while-idle: true test-on-borrow: false test-on-return: false # 连接池监控统计 filters: stat,wall,log4j2

两个重点。

第一个是 URL 里的schema=RUOYI。达梦的连接串可以不带 schema,默认使用用户名对应的模式,但如果你在用户名上踩了大小写坑,显式指定 schema 是最直观的排查方式。

第二个是validation-query。MySQL 默认是SELECT 1,达梦其实也支持,但我见过一些低版本驱动在连接初始化时对SELECT 1处理有兼容问题,统一改成SELECT 1 FROM DUAL最稳妥,不影响性能。

filters里的wall要特别注意。Druid 的防火墙插件对达梦的语法支持不像对 MySQL 那么完善,个别 SQL 会被误判为非法 SQL 拦截。如果你启动时看到类似sql injection violation, part alway true condition not allow这种异常,优先怀疑 wall filter,临时把filters改成stat验证一下,确认是误杀后再决定要不要保留。

4.2 PageHelper 方言配置

若依的application-druid.yml里本来就有这一段:

pagehelper: helper-dialect: mysql reasonable: true support-methods-arguments: true params: count=countSql

直接把helper-dialectmysql改成dm就行:

pagehelper: helper-dialect: dm reasonable: true support-methods-arguments: true params: count=countSql

有人会问:PageHelper 不是号称能自动识别数据库类型吗?为什么还要手动指定?我实测下来,jdbc:dm这个 URL 在 PageHelper 的自动识别里经常失效,它会把达梦误判成未知库,然后默认走标准 JDBC 分页或直接拼错 SQL。手动指定dm一劳永逸。

如果你不想依赖 Spring Boot Starter 的自动装配,也可以在mybatis-config.xml里手动注册PageInterceptor

<plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"> <property name="helperDialect" value="dm"/> <property name="reasonable" value="true"/> </plugin> </plugins>

两种方式二选一,不要同时配两遍,否则分页会被执行两次,列表接口返回的 total 和 pages 会异常。

4.3 打包时别把驱动丢在外面

systemPath引入的 jar 在打包阶段容易被 spring-boot-maven-plugin 忽略,最终打出的可执行 jar 里没有达梦驱动,启动就报ClassNotFoundException。解决办法是在spring-boot-maven-plugin里加上includeSystemScope配置:

<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <includeSystemScope>true</includeSystemScope> </configuration> </plugin>

不配置这个,本地 IDE 跑得通,java -jar直接翻车。这个坑我当时找了半小时,差点以为驱动文件损坏。

5. 代码生成器适配:从information_schema切换到系统视图

5.1 问题根源

若依的代码生成器是它的一大卖点,但也是迁到达梦后最容易崩的地方。它默认通过information_schema.tablesinformation_schema.columns来读取数据库里有哪些表、字段类型、注释等信息。达梦没有information_schema,或者说不提供与 MySQL 完全一致的information_schema语义,所以打开代码生成页面时,表列表经常是空的,或者直接报错。

这个问题的典型报错长这样:

com.dameng.jdbc.DMException: 第 1 行, 第 100 列附近出现错误: 表或视图不存在: information_schema.tables

5.2 改成达梦字典表

达梦兼容 Oracle 风格的数据字典视图,用user_tab_commentsuser_tab_columns可以替代information_schema。我直接改了GenTableMapper.xml里查询表列表的 SQL。

原 MySQL 写法大概是这样:

select table_name, table_comment, create_time, update_time from information_schema.tables where table_comment is not null and table_schema = 'ruoyi'

改成达梦:

SELECT t.table_name, c.comments AS table_comment, NULL AS create_time, NULL AS update_time FROM user_tables t LEFT JOIN user_tab_comments c ON t.table_name = c.table_name WHERE c.comments IS NOT NULL ORDER BY t.table_name

注意user_tablesuser_tab_comments查出来的都是大写表名。如果初始化建表时统一没加引号,那么表名都是大写的,查询没问题。如果哪张表当初是用双引号建的小写名,这里就找不到,需要额外处理。

查询表字段的 SQL 也要改。默认的 Mapper 查information_schema.columns来获得列名、类型、长度、注释,达梦版可以写成:

SELECT c.column_name, c.data_type, c.data_length, c.nullable, c.column_id, cm.comments AS column_comment FROM user_tab_columns c LEFT JOIN user_col_comments cm ON c.table_name = cm.table_name AND c.column_name = cm.column_name WHERE c.table_name = #{tableName} ORDER BY c.column_id

这套 SQL 和 Oracle 基本一样,跑一次就能把若依代码生成器的表结构元数据读取拉回来。

5.3 GenUtils 的类型映射也要补

代码生成器拿到列类型后,会走GenUtils.java里的方法把数据库类型映射成 Java 类型。varcharbigintdatetime这些常见类型两边都有,不需要动。但达梦里返回的类型名可能是CLOBVARCHAR2TIMESTAMP这类,如果GenUtils里没有对应映射,生成代码时会出现Unsupported data type或直接生成Object字段。

我在GenUtilscolumnTypeToJavaType方法里补过一段映射:

if ("clob".equals(columnType) || "text".equals(columnType) || "longtext".equals(columnType) || "varchar2".equals(columnType)) { return "String"; } else if ("timestamp".equals(columnType) || "datetime".equals(columnType)) { return "Date"; } else if ("number".equals(columnType) || "decimal".equals(columnType)) { return "BigDecimal"; }

改完重新启动,进入“系统工具-代码生成”,选择表后点“预览”,基本就能正常生成 controller、service、mapper 等全套代码了。

6. 启动联调实录:三个高频报错与定位过程

最后分享几个我在实际跑通过程中真实撞上的问题。这三个问题非常有代表性,如果你也是从 MySQL 迁达蒙,大概率会碰见其中一个。

6.1 启动时 Druid 初始化失败:Failed to execute validationQuery

先出现的是这个:

com.alibaba.druid.pool.DruidDataSource - {dataSource-1} closed validateConnection false

意思是连接池校验失败了。一开始我怀疑是账号密码问题,但用 DM 管理工具用同样的用户名密码连接是正常的。后来逐项排查,发现问题出在validation-query。当时配置还留着 MySQL 时代的SELECT 1,改成了SELECT 1 FROM DUAL,启动立刻恢复。这个问题的误导性在于,有些版本下SELECT 1也能通过,导致不少人把排查方向带偏到用户名密码上。

6.2 复杂 SQL 报 LIMIT 语法错误

启动成功后,打开“系统管理-用户管理”,列表接口直接报:

dm.jdbc.driver.DMException: 第 1 行, 第 200 列, LIMIT 附近出现错误: 语法分析出错

一看这个报错,第一反应该是 PageHelper 方言没生效,而不是急着去改 Mapper。我先检查application-druid.yml,发现pagehelper.helper-dialect还是mysql。改成dm后重启,这个报错就消失了。

但紧接着又出现第二个关联问题:若依的用户列表 SQL 本身没有手写 LIMIT,而我在排查过程中把某个 Mapper 里的LIMIT 1手动改成了FETCH FIRST 1 ROWS ONLY,所以后续没再触发同类问题。建议思路是:先确保 PageHelper 方言正确,再逐个排查 XML 里有没有裸写LIMIT,不要反着来。

6.3 代码生成页面不显示任何表

登录系统后打开代码生成页面,发现列表空空如也。这个方法我刚才已经写过,根因就是information_schema不存在。但在实际排查时,这个报错有迷惑性——因为前端接口返回的是空数组,不仔细看后端日志根本不知道是 SQL 执行失败。我是在后台日志里看到表或视图不存在: information_schema.tables才锁定位置的。

GenTableMapper.xml里的查询换成user_tablesuser_tab_comments后,页面立刻正常。补了GenUtils的 CLOB 映射后,代码生成预览也恢复正常。

6.4 联调验证清单

改造完成后,我没有只测一个登录就收工,而是按业务主链路过了一遍,建议你也照着验证:

  • 登录、验证码校验、权限菜单展示
  • 新增用户、分配角色、重置密码
  • 部门、岗位、字典的增删改查
  • 使用代码生成器生成一套包含单表查询的代码并跑起来
  • 手动触发一次定时任务,确认qrtz_表正常写入
  • 删除一条带关联数据的记录,确认事务回滚没有异常

这里面的任何一步有问题,多半还是 SQL 方言或类型映射的问题,回到第 3 节和第 5 节的表格里对照排查即可。

整个迁移做下来,我最深的体会是:换数据库这件事,真正的成本不在“连接”而在“语义”。若依的代码里悄悄依赖了太多 MySQL 专属语法,这些不会在编译期暴露,只会在运行时一点点冒出来。把 Mapper SQL、分页方言、代码生成器三个核心点一次改到位,后面反而顺风顺水。如果你也在迁达梦,希望这份源码级的改造记录能帮你把一周的活压缩成一天。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 17:24:50

Python零基础实战:环境报错、import与类型转换坑点全解析

很多人在学完前两篇笔记后&#xff0c;会有一种“知识都懂&#xff0c;代码全懵”的阶段。循环会写了&#xff0c;函数会用了&#xff0c;列表字典也能操作了&#xff0c;但真要自己独立写点东西&#xff0c;却发现环境老是报错&#xff0c;import 一个模块不是没人认就是装不上…

作者头像 李华
网站建设 2026/9/8 17:19:03

Bambu Studio手办强度设置全解析:填充、外壳与切片参数实战

前两天群里又有朋友发图&#xff1a;一只打印完的手办&#xff0c;从脚踝到小腿那段直接齐根断成两截。我看了眼切片截图就知道问题出在哪——模型20%填充没错&#xff0c;但壁厚只有1.2mm&#xff0c;顶底层数也压到了最低&#xff0c;整体就靠着几根稀疏填充在硬扛。很多人打…

作者头像 李华
网站建设 2026/9/8 17:18:52

搜广推策略产品经理读书笔记:从底层框架到实战方法论

简介&#xff1a;围绕《搜广推策略产品经理》一书的读书笔记压缩包&#xff0c;面向搜索广告、推荐系统领域的策略产品经理、产品运营、数据分析师及初入职场者。笔记梳理了策略PM的职责定位、市场研究、竞品分析、需求收集、策略设计、数据监控、效果评估与优化迭代等核心工作…

作者头像 李华
网站建设 2026/9/8 17:16:50

具身智能算力选型避坑指南:从TOPS到功耗散热的实测经验

谁在选型具身智能算力板子的时候没被数据手册坑过&#xff0c;站出来我看看。我去年接手一个室外无人巡检车项目&#xff0c;摄像头加激光雷达加机械臂协同&#xff0c;老板要求端侧跑完整个感知-规划-控制链路&#xff0c;不能依赖5G回传云端计算。当时天真地以为“算力嘛&…

作者头像 李华