简介:这是若依开源框架全面适配达梦数据库的完整源码包,面向正在使用若依构建企业应用、又需要切换到国产化数据库环境的技术团队,可绕开数据库驱动、方言和事务兼容等集成过程中的常见障碍。整个压缩包共635个文件、体积约4.66MB,文件类型覆盖面较广:253个Java源码构成后端业务逻辑,124个HTML配合83个JS与42个CSS完善前端交互,另有XML/YML配置、SQL脚本、VM模板、PNG/GIF图标、bat/sh启动脚本与JAR驱动包,可支撑代码阅读、二次开发直至环境部署。内容除完整工程外,还包含达梦库表结构设计说明与典型SQL适配示例,并用PDM建模文件辅助理解表关系,帮助读者快速定位连接池、事务管理与分页查询等需要调整的位置。已有3032人学习下载,适合具备一定若依基础、希望引入达梦数据库的开发者作为落地参考资料。
1. 项目概述:为什么若依要适配达梦数据库
做国产化项目这行当久了,你会碰上一个绕不开的组合:若依框架加达梦数据库。若依(RuoYi)在国内开发圈的分量不用多说,基于Spring Boot加MyBatis的快速开发平台,前后端分离版本、微服务版本都在大量生产项目里跑着。而达梦数据库(DM8)作为国产数据库里出货量第一梯队的选手,在政务、军工、金融这些强调信创的行业里几乎是标配。
这两者适配的核心矛盾在于:若依框架从诞生那天起就是为MySQL服务的,无论是默认的SQL语法、分页插件、代码生成器的模板,还是定时任务里默认调用的存储函数,全都写着MySQL的烙印。你直接把若依的SQL脚本丢给达梦执行,大概率会在建表语句的注释语法、字段类型映射、自增主键定义这几个地方卡住,接着在联调阶段陆续踩中分页SQL方言不兼容、函数不存在、排序规则不一致这些暗坑。因此,把若依完整迁移到达梦数据库,不只是一份SQL脚本改一改那么简单,而是要从建表、持久层SQL、配置文件、ORM方言、定时任务兼容、代码生成器这六个维度做一次系统性适配。
这篇文章基于我实际做完的一个若依前后端分离版本集成达梦8的完整项目,把源码层面的改造思路、关键配置、踩坑记录全部整理出来。适合两类读者:一类是正在做信创适配、被甲方要求数据库必须换成达梦的Java开发,另一类是打算在国产技术栈上从零搭建项目的团队。照着这篇文章的思路走一遍,你手头的若依项目大概率一天之内就能在达梦上跑起来。
2. 整体设计思路与适配方案选型
2.1 明确适配边界:改哪些、不改哪些
在做任何技术适配之前,最忌讳的就是一上来就闷头改代码。我在拿到这个任务时,先花了一个下午把若依源码里跟数据库相关的部分全部扫了一遍,用依赖梳理的方式把改造边界摸清楚。
若依框架和数据库交互的链路,从配置文件到SQL执行,一共涉及五层:pom.xml依赖管理、application-druid.yml数据源配置、MyBatis Mapper接口与XML文件、代码生成器模板、定时任务脚本(Quartz的表结构和调用函数)。在这些层里,有一部分是必须改的,比如建表SQL、数据源驱动配置、个别SQL方言;还有一部分是不需要大动的,比如业务模块里90%以上的CRUD操作,因为MyBatis在底层已经帮你把大部分参数绑定和结果集映射做掉了。
这里说个重要的选型判断。完备的适配方案有两种姿态:一种是只做"能跑起来"级别的最小改动,把MySQL的SQL脚本手工翻译到达梦语法,改完配置就交差;另一种是做"物尽其用"级别的深度适配,还想办法把达梦的Oracle兼容模式、行列存储引擎这些高级特性用起来。如果项目只是验收性质的信创适配,前者就够了。但如果你打算在达梦上长期稳定运行,我的建议是直接按后者来,因为前者的埋坑风险会在后续的功能迭代、报表统计、数据迁移中反复爆雷。我这次做的改造,最终落在了一个折中方案上:核心框架全面适配,业务代码最小侵入。
2.2 达梦数据库与MySQL的核心差异
聊适配之前,有必要把达梦数据库跟MySQL之间的几个关键差异讲透。搞懂了这些差异,你就明白后面每一步改造为什么要那么写了。
第一点是SQL方言体系。达梦数据库虽然也兼容MySQL协议,但它的底层更接近Oracle的语法逻辑。默认安装的达梦8,兼容模式一般建议选"MySQL",这样LIMIT分页、反引号字段名这些写法还能用。但问题是,如果达梦装在Oracle模式下,或者有些生产库为了兼容老系统切换到Oracle模式,那若依自带的MySQL风格分页SQL就全废了。我这次测试环境用的是MySQL兼容模式,属于最省心的状况,但即便如此,还是有不少MySQL专属函数在达梦里找不到对应实现。
第二点是字段类型映射。若依的建表SQL是MySQL风格,varchar、datetime、longtext、int(11)这类写法在达梦里都有对应类型,但细节匹配有讲究。举个例子,MySQL的datetime和达梦的datetime都可以用,但达梦更推荐timestamp;MySQL的tinyint(1)表示布尔值,达梦里实际上会映射成smallint还是tinyint得看兼容参数配置。更麻烦的是text、longtext这类大字段类型,达梦里对应的是TEXT和CLOB,如果你在改造时配错了,插入超长字符串会直接报错。
第三点是自增主键和序列。MySQL的AUTO_INCREMENT在达梦里同样支持,但达梦更原生的是SEQUENCE(序列)+ 触发器的方式。若依的多数表用的都是自增主键,所以建表SQL里AUTO_INCREMENT要保留,但如果你用的是达梦Oracle模式,就必须改用序列加触发器。
第四点是函数和运算符差异。这是最容易踩坑的地方。MySQL里的IFNULL、DATE_FORMAT、GROUP_CONCAT、CURDATE这些函数,在达梦里要么不支持、要么函数名不一样。达梦有NVL、TO_CHAR这类Oracle风味的函数。这意味着若依Mapper XML里的若干SQL片段,需要手工改写。
2.3 适配方案的总体架构
整个适配工作我在计划阶段拆成了四个阶段,分别是准备、改造、联调、验证。准备阶段要做的事情是搭环境、初始化达梦实例、导入原文的MySQL脚本,先跑一遍看看报什么错,把错误清单作为改造的输入。改造阶段关注代码和SQL脚本,按依赖层逐个击破。联调阶段是启动若依前后端项目,走一遍登录、菜单、权限、增删改查、代码生成的完整链路。验证阶段重点压一下并发、大批量数据导入和定时任务执行,确认不会在运行几天后突然出幺蛾子。
每个阶段的产出物都是下一阶段的输入,比如准备阶段的错误清单直接决定改造阶段的优先级,联调阶段的报错日志又补充到排查手册里。这个流程走下来,整个适配过程是可控的,而不是走一步看一步。
3. 核心源码改造实操:从建表到Java代码逐层适配
3.1 环境准备与达梦数据库初始化要点
在动手改代码之前,先把环境准备好。达梦8的安装包从官网申请试用版就行,Windows和Linux都有对应的安装包。我这里用的是Linux服务器部署,安装步骤不复杂,重点是初始化实例时的几个参数选择。初始化实例时,有一个"数据库兼容模式"的选项,下拉菜单里有MySQL、Oracle、SQL Server等选项,这里务必选MySQL兼容模式。如果你已经装好了才发现模式不对,也不是完全没法补救,但后续会遇到一堆莫名其妙的SQL兼容问题,强烈建议重装。
安装完成后,用达梦自带的manager管理工具创建一个业务数据库,这个库对应若依里的ry-vue这个schema。紧接着做一件关键的事情:把若依项目里的sql/ry_2024xxxx.sql(MySQL版本)找出来,先用达梦的迁移工具或者手工方式执行一遍。你会看到第一批报错信息,大致包括注释语法不支持、字段类型不识别、索引名重复这几类。这些报错信息很有价值,建议截图存档,因为后面每一步改造其实就是在消灭这些报错。
补充一个很实用的建议:达梦8安装完了之后,默认会开一个叫做"模式"的概念,Oracle风格的模式对应MySQL的数据库(schema)。而若依项目里的数据源URL写的是jdbc:dm://localhost:5236,默认连的是达梦的SYSDBA模式。如果你不希望业务表都建在SYSDBA模式里,最好在manager工具里新建一个模式,建表和授权都放在这个新模式下,后面JDBC URL里也可以指定schema。
3.2 数据源配置改造(Druid连接池与驱动)
若依的数据源配置集中在resources/application-druid.yml这个文件里。MySQL版本下的默认配置,driverClassName是com.mysql.cj.jdbc.Driver,url是jdbc:mysql://localhost:3306/ry-vue。要切换到达梦,这两行配置需要改掉:
# application-druid.yml 关键片段 spring: datasource: druid: driverClassName: dm.jdbc.driver.DmDriver url: jdbc:dm://localhost:5236?schema=RUOYI username: SYSDBA password: ******这里有两处细节特别容易出错。第一,达梦的JDBC驱动包不在Maven中央仓库里,需要从达梦安装目录的drivers/jdbc目录里找到DmJdbcDriver18.jar(对应JDK8及以上),用mvn install:install-file命令手动安装到本地仓库,然后才能在pom.xml里正常依赖。命令参考如下:
mvn install:install-file -Dfile=DmJdbcDriver18.jar -DgroupId=com.dameng -DartifactId=DmJdbcDriver18 -Dversion=8.1.2.192 -Dpackaging=jar然后在若依的父pom或ruoyi-framework模块pom里,加入这个依赖坐标。注意不要盲目改成spring-boot-starter-jdbc自带的驱动加载方式,因为若依的Druid配置里还有很多监控相关的参数,沿用druid-spring-boot-starter最稳妥。
第二,MySQL兼容模式下,Druid的wall(防火墙)过滤器有可能会拦掉一些达梦特有的SQL写法。如果启动时报错提示"sql injection violation",可以在Druid配置里把wall的配置放宽:
spring: datasource: druid: filter: wall: enabled: true config: multiStatementAllow: true noneBaseStatementAllow: true不过这里我不建议把wall完全关掉,做信创项目时安全合规审计往往会查这个开关。用multiStatementAllow就够了。
3.3 建表SQL脚本的达梦方言重写
这是整个改造中工作量最大的部分。若依原生的MySQL建表脚本分成两部分:框架核心表(sys_user、sys_role、sys_menu这些)和业务示例表。框架核心表是必须手动改写的,因为后续若依的登录、权限模块全都依赖这些表的结构,任何字段类型错误都会在联调时暴露出来。
我在实际操作中,采用了一边建一边跑的方式:先用达梦manager工具手动把框架核心表建好,然后在若依的后端配置里把数据源切过去,挨个启动模块看报错。这个过程有点笨,但排查效率最高。下面把最常见的几类建表差异整理出来:
第一类是注释写法不同。MySQL里字段注释和表注释都写在字段定义后面,用COMMENT 'xxx',而达梦MySQL兼容模式也支持这种写法,但如果你遇到个别版本报错,可以把COMMENT单独放在建表语句之后:
-- MySQL风格(达梦MySQL兼容模式通常可用) CREATE TABLE sys_user ( user_id int NOT NULL AUTO_INCREMENT COMMENT '用户ID', user_name varchar(30) NOT NULL COMMENT '用户账号', PRIMARY KEY (user_id) ) COMMENT = '用户信息表'; -- 达梦兼容写法 CREATE TABLE sys_user ( user_id INT IDENTITY(1,1) NOT NULL, user_name VARCHAR(30) NOT NULL, PRIMARY KEY (user_id) ); COMMENT ON TABLE sys_user IS '用户信息表'; COMMENT ON COLUMN sys_user.user_id IS '用户ID';IDENTITY是达梦的自增语法。如果你在MySQL兼容模式下使用AUTO_INCREMENT也能通过,但Oracle模式下只能用IDENTITY或序列。为了适配面更广,我最后把核心表统一改成了IDENTITY写法。
第二类是字段类型映射。若依里大量的datetime、longtext、int(11)类型,建议在达梦里全部显式改成timestamp、text、int。特别是longtext这个类型在达梦里不存在,直接改成CLOB或者TEXT,如果用的是TEXT类型,要注意它的长度上限,达梦的TEXT对应MySQL的MEDIUMTEXT级别,一般够用。
第三类是索引名和约束名的全局唯一问题。若依原生脚本里索引名比较随意,比如idx_name、idx_order等,在MySQL里同一个库下可以重复,但在达梦里索引名的唯一性要求更严格。建议在改写时给索引统一加表名前缀。
3.4 Mapper XML中的SQL方言适配
若依的核心Mapper XML文件里,虽然大多数是简单的CRUD操作,但有几个文件里藏着MySQL专属语法。根据我实际的代码检索结果,需要重点排查的有三个文件。
第一个是SysUserMapper.xml,里面有个selectUserList的查询方法,用了大量的条件拼接,其中有IFNULL函数。达梦在MySQL兼容模式下提供了IFNULL的别名实现,所以这个偶尔能跑过。但保险起见还是改成NVL,达梦对NVL的支持更原生。
第二个是SysMenuMapper.xml,它的菜单权限SQL里用到了DATE_FORMAT函数来格式化和排序菜单时间。如果只是格式展示,可以在Java层用SimpleDateFormat处理,SQL里直接去掉函数。我在改造时选择了后者,减少SQL层面的方言依赖。
第三个是通用分页查询。若依默认使用PageHelper做物理分页,PageHelper的dialect配置需要切换成达梦方言。在application.yml里的PageHelper配置段,设置helperDialect为dm:
pagehelper: helperDialect: dm reasonable: true supportMethodsArguments: true params: count=countSql如果不配置这个,PageHelper会根据URL自动识别数据库类型,有些版本识别不了达梦会退回MySQL方言,生成的COUNT查询和分页SQL都用LIMIT语句,达梦在MySQL兼容模式下看着能跑,但实际的物理分页采用的是达梦的LIMIT实现,性能上可能会有偏差。手动指定dm方言之后,PageHelper会用达梦特有的分页语法生成SQL,跑起来更稳。
再补一个容易忽略的坑:若依的代码生成器模块(ruoyi-generator)里,有从数据库读取表结构生成代码的逻辑,它查询表元数据的SQL也是MySQL风格(读取information_schema.COLUMNS),遇到达梦时这里需要单独改造。具体来说,在GenTableMapper.xml和GenTableColumnMapper.xml里,有两段查询表结构和列信息的SQL,需要改成查询达梦的系统视图,常见写法是:
SELECT COLUMN_NAME, DATA_TYPE, COLUMN_COMMENT FROM ALL_TAB_COLUMNS WHERE TABLE_NAME = #{tableName}这里要说明一下,ALL_TAB_COLUMNS在达梦中是存在的(Oracle兼容的系统视图)。若依代码生成器改造完之后,你才能在页面上继续用"导入表"功能。不常写代码生成器的同事可能注意不到这里,但真正用来一导报表单就报错,查半天都在查XML语法,纯粹浪费时间。
3.5 Quartz定时任务与达梦的兼容处理
若依自带了一套基于Quartz的定时任务模块,对应的quartz.sql脚本里有十几张Quartz框架表。这套脚本在达梦里运行完会有几处报错,集中在BLOB、CLOB类型的默认值以及索引长度超限上。我的处理经验是:不要在达梦里手动建这十几张表,而是直接在Quartz的持久化配置里,把quartz的jobStore切换成达梦友好配置。
具体做法是,若依的application.yml里有一段spring.quartz的配置,默认情况下若依把Quartz的jobStore设置成了JDBCJobStore,同时使用数据库表存储任务。在达梦环境下,你需要确认Quartz的驱动代理类可以正常工作。通常遇到的是如下报错:
org.quartz.impl.jdbcjobstore.LockException: Failure obtaining db row lock: 达梦数据库锁表现异常这个报错的原因多半是Quartz的默认锁机制(select ... for update)在达梦上锁表失败,解决办法是把quartz.properties里配置两个关键参数:
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.isClustered=false org.quartz.jobStore.tablePrefix=QRTZ_如果你不需要集群部署,isClustered设为false能避免大部分锁问题。如果一定要集群模式,那需要仔细检查QRTZ_LOCKS表的存在性和表结构,保证select for update能正常执行。
4. 集成过程中高频问题与排查实战记录
4.1 驱动加载失败或ClassNotFoundException
这是一个出现频率极高的问题。报错内容通常是dm.jdbc.driver.DmDriver这个类找不到。排查步骤三步走:第一步检查pom依赖是否已经引入DmJdbcDriver18,第二步检查Maven本地仓库里是否有这个jar(用mvn dependency:tree查看),第三步确认打包方式。如果你是把若依打成可执行jar部署,要确认DmJdbcDriver18的jar确实打进去了,可以在解压后的BOOT-INF/lib目录里找到它。
出现这个问题的根本原因基本都出在手动安装jar这一步。普通JDBC驱动jar如果有pom文件的话还好,达梦的驱动jar在安装目录里没有pom,mvn install时你需要手工指定groupI、artifactId、version。如果指定的坐标跟pom.xml里写的不一致,启动时类加载自然失败。
4.2 中文乱码与字符集设置
达梦数据库的字符集默认跟安装时操作系统环境有关,如果安装时选了GBK,而你项目里用UTF-8,查询出的中文就会乱码。解决办法是在达梦manager工具里新建数据库时,把字符集明确设置为UTF-8。已建好的库可以通过修改实例参数调整,但不建议在生产环境这么干,风险较大。
另外,JDBC URL上有必要加上字符集参数。达梦的驱动会读取连接串里的encoding或characterEncoding参数,例如:
url: jdbc:dm://localhost:5236?schema=RUOYI&characterEncoding=utf-84.3 分组查询时出现"不是GROUP BY表达式"错误
这个问题在从MySQL迁到达梦时几乎必现。原因是MySQL的sql_mode默认允许select列不在group by中出现,而达梦更严格,要求select列表里的非聚合列都必须出现在group by子句中。若依的菜单表、岗位表里多少有几个这类统计SQL,遇到之后老老实实改写SQL,把非聚合列加进group by,或者改成子查询方式。
举个例子,SysMenuMapper.xml里有一个查询菜单列表并关联用户表的SQL,它会select出多张表的字段,group by却只写了菜单表主键。原样跑MySQL没问题,到达梦就报错。改法是查出业务字段后group by全部字段列表,或者把统计字段用min/max包裹。
我把这类问题整理成一个高频速查表:
| 问题现象 | 根因 | 解决方案 |
|---|---|---|
| ClassNotFoundException: DmDriver | 驱动jar未正确引入 | 手工mvn install并核对坐标 |
| 建表时COMMENT语法报错 | 达梦模式对注释写法要求严 | 改用COMMENT ON TABLE/COLUMN语法 |
| 分页SQL用了LIMIT报错 | PageHelper方言识别异常 | 手动指定helperDialect=dm |
| select中出现非聚合列且未group by | 达梦对分组查询校验严格 | 改写SQL补齐group by字段 |
| 定时任务报锁表异常 | Quartz集群锁在达梦上的兼容问题 | 关闭集群模式或维护QRTZ_LOCKS表 |
| 插入大文本报字段超长 | MySQL的longtext被映射为CLOB,长度限制变化 | 改TEXT类型或者调整达梦参数 |
| 代码生成器导入表列表为空 | 默认查询information_schema不兼容 | 改造GenTableMapper查询系统视图 |
4.4 若依微服务版本与Flowable工作流适配
如果你的项目用的是若依微服务版本,改动逻辑类似但文件更分散,每个微服务模块都有自己的数据源配置和SQL脚本。你需要在gateway、system、auth等各个服务里重复做数据源切换。另外,如果集成了Flowable工作流引擎,Flowable 6.7.2对达梦的适配有官方补丁,它是通过flowable-dm-dialect之类的方言包实现的,在你的pom里单独引入flowable的达梦方言依赖后,把ProcessEngineConfigurationConfigurer里的databaseType设置为dm即可。
Nacos如果也要使用达梦作为存储,官方提供的MySQL存储脚本不能直接用,达梦社区有适配脚本。不过Nacos的默认存储目前还是内置Derby或MySQL,达梦适配需要动Nacos源码,一般建议维持Nacos用MySQL,核心业务数据用达梦,这样集成成本可控。
5. 实操心得与后续扩展建议
最后聊几点我在这个项目里踩出来的实在心得。
第一点,如果你是要交付给甲方的信创适配项目,不要只提供改好的源码,还要整理一份"MySQL到达梦数据库改造对照说明",把每个文件的改动点、改动原因、验证结果都列出来。这份文档在验收评审时能省掉大量解释成本,也方便后来人快速接手。
第二点,代码生成器这层改造很容易被忽略,但不改的话,后期甲方会拿它来快速生成业务CRUD,一用就报错,体验极差。所以无论项目时间多紧,这层一定要动。
第三点,测试阶段建议专门留一天做"回归SQL对比"。用同样一批数据,在MySQL和达梦上分别跑一遍若依的全部功能,把两边的查询结果做diff,你会发现有些SQL虽然两边都不报错,但结果集的排序或字段默认值不一样。这类隐蔽问题不在联调阶段抓出来,上线后就会变成数据不准的投诉。
再补充一个后续扩展的方向:达梦8自身支持Oracle模式和MySQL模式的双模切换,你可以研究一下让同一个若依系统在这两种模式下都能运行。思路是在MyBatis层封装一套针对不同数据库方言的StatementProvider,或者直接在XML里用<databaseId>标签指定不同数据库的SQL。若依目前的代码没有利用MyBatis的databaseId机制,但这块儿改动不大,值得做。这样一来,你的项目就真正做到了数据库无关,未来无论遇到什么信创数据库要求,都能快速响应。
本文还有配套的精品资源,点击获取