简介:若依框架与达梦数据库的集成源码包,面向需要在国产化环境下搭建企业级应用的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.sql等 | ENGINE=InnoDB、AUTO_INCREMENT等语法必须改写 |
| Mapper XML | 大量 MySQL 函数和分页写法 | IFNULL、DATE_FORMAT、LIMIT等需要兼容处理 |
| 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) | 完全兼容 |
datetime | DATETIME | 达梦支持,也可用TIMESTAMP |
tinyint(1) | TINYINT | 兼容,但代码里可能转 Boolean,需留意 |
text | TEXT或CLOB | 建议直接上CLOB,兼容性最好 |
longtext | CLOB | 若依里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, b | OFFSET 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 VARCHAR、BLOB这些类型。若依的 Quartz 逻辑本身不涉及数据库方言,表一建,任务调度就能跑。如果找不到这个脚本,也可以把 MySQL 脚本里的engine=innodb和comment全删掉,varbinary改VARBINARY或BLOB,手工处理也能过。
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-dialect从mysql改成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.tables和information_schema.columns来读取数据库里有哪些表、字段类型、注释等信息。达梦没有information_schema,或者说不提供与 MySQL 完全一致的information_schema语义,所以打开代码生成页面时,表列表经常是空的,或者直接报错。
这个问题的典型报错长这样:
com.dameng.jdbc.DMException: 第 1 行, 第 100 列附近出现错误: 表或视图不存在: information_schema.tables5.2 改成达梦字典表
达梦兼容 Oracle 风格的数据字典视图,用user_tab_comments和user_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_tables和user_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 类型。varchar、bigint、datetime这些常见类型两边都有,不需要动。但达梦里返回的类型名可能是CLOB、VARCHAR2、TIMESTAMP这类,如果GenUtils里没有对应映射,生成代码时会出现Unsupported data type或直接生成Object字段。
我在GenUtils的columnTypeToJavaType方法里补过一段映射:
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_tables和user_tab_comments后,页面立刻正常。补了GenUtils的 CLOB 映射后,代码生成预览也恢复正常。
6.4 联调验证清单
改造完成后,我没有只测一个登录就收工,而是按业务主链路过了一遍,建议你也照着验证:
- 登录、验证码校验、权限菜单展示
- 新增用户、分配角色、重置密码
- 部门、岗位、字典的增删改查
- 使用代码生成器生成一套包含单表查询的代码并跑起来
- 手动触发一次定时任务,确认
qrtz_表正常写入 - 删除一条带关联数据的记录,确认事务回滚没有异常
这里面的任何一步有问题,多半还是 SQL 方言或类型映射的问题,回到第 3 节和第 5 节的表格里对照排查即可。
整个迁移做下来,我最深的体会是:换数据库这件事,真正的成本不在“连接”而在“语义”。若依的代码里悄悄依赖了太多 MySQL 专属语法,这些不会在编译期暴露,只会在运行时一点点冒出来。把 Mapper SQL、分页方言、代码生成器三个核心点一次改到位,后面反而顺风顺水。如果你也在迁达梦,希望这份源码级的改造记录能帮你把一周的活压缩成一天。
本文还有配套的精品资源,点击获取