ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Spring Boot + MyBatis Plus 迁移达梦数据库(DM8)实战与踩坑记录

Spring Boot + MyBatis Plus 迁移达梦数据库(DM8)实战与踩坑记录 最近把一套跑在 MySQL 上的 Spring Boot 项目迁到了达梦数据库DM8底层 ORM 用的本来就是 MyBatis Plus整个过程比预想中要折腾不少。Spring Boot MyBatis Plus 达梦数据库这套组合很多文章只说“把 driver-class-name 换成 dm.jdbc.driver.DmDriver 就行”但实际上分页、关键字、主键策略、驱动版本这些环节都会跳出来卡你一下。这篇就把我从环境准备、依赖配置到分页排查、批量操作、管理工具连库的完整过程写出来希望可以帮正在做信创适配或数据库替换的人少走几个弯路。1. 先搞清楚达梦数据库的定位很多坑都出在“惯性思维”1.1 达梦和 Oracle、MySQL 的真实关系达梦不是 MySQL 的套壳它更像 Oracle有表空间、用户即模式schema、支持 PL/SQL 风格的过程和函数、有 ROWNUM 这类伪列。同时达梦也做了一套 MySQL 兼容模式甚至允许你在 SQL 里使用反引号和 LIMIT。问题就出在这个“兼容”上很多从 MySQL 迁过来的团队默认把它当 MySQL 用结果在分页、批量 INSERT、字段类型、保留字上接连踩坑。我的经验是先确认当初初始化数据库实例时选的是哪种兼容模式达梦安装时可以选 Oracle 模式还是 MySQL 模式后面排查会轻松很多。如果建库时选的是 Oracle 模式那 SQL 写法、工具行为都更贴近 Oracle如果选了 MySQL 模式LIMIT 这类语法会好用一些。不要把两种模式混在一起猜不然你很难判断某个报错到底是语法问题还是驱动问题。1.2 版本配套Spring Boot 2.x 和 3.x 要分开选依赖集成前最容易忽略的是版本对应关系。网上很多老教程里还是mybatis-plus-boot-starter版本停在 3.4.x如果你用的是 Spring Boot 3.2 甚至更高版本是跑不起来的会出现 AutoConfiguration 找不到、jar 包冲突或者连SqlSessionFactory都创建失败。结合搜索词里被频繁提到的“springboot版本太高”这确实是这两年问得最多的问题。我实际测试过的最低稳定组合是组件推荐版本说明Spring Boot 2.7.x2.7.18用mybatis-plus-boot-starterJDK 8 可跑兼容性最稳Spring Boot 3.2.x3.2.5 等必须用mybatis-plus-spring-boot3-starterJDK 17 起步MyBatis Plus3.5.5 以上内置DbType.DM达梦方言分页插件直接支持达梦 JDBC 驱动DmJdbcDriver18 8.1.2.x / 8.1.3.x尽量和达梦数据库小版本保持一致如果你还在用旧的 MyBatis Plus 3.4.x建议先升级否则后面分页配置里可能找不到DbType.DM只能被迫用DbType.MYSQL顶上这种方案我不太推荐因为达梦的 LIMIT 解析在特殊场景下和 MySQL 还是有差异。1.3 达梦安装、实例初始化和管理工具的使用细节达梦在 Windows 下安装比较简单安装包解压后点安装程序跟着向导走就行。真正需要注意的是这几个点实例端口默认是 5236不是 3306 也不是 1521。字符集建议选 UTF-8除非你已经确定历史库是 GBK。大小写敏感这个选项会直接影响表名和数据建议从第一天就统一用大写建表。初始密码、模式名这些信息要记好后面连数据库、导数据都会用到。有用户提到“达梦数据库 dm 管理工具没有对象导航栏”我也遇到过。DM管理工具连接上数据库后如果左侧对象导航栏整块不见了先检查菜单栏里的“视图”相关选项把对象导航窗口重新调出来如果能看到导航栏但展开后没有表通常是因为当前连接在模式下拉框里没有选中那个模式。达梦的用户和模式是绑定的你用 SYSDBA 登录能看到所有模式但要展开对应的用户模式才能看到表和视图。用其他业务账号登录时要确认该账号对目标模式有访问权限否则列表里是空的。2. 项目里的依赖引入和数据源配置细节都在配置里2.1 Maven 依赖怎么加达梦驱动大概率要手动装到本地仓库先看 Spring Boot 2.7.x 项目里的依赖写法dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.5/version /dependency dependency groupIdcom.dameng/groupId artifactIdDmJdbcDriver18/artifactId version8.1.2.192/version /dependency如果用的是 Spring Boot 3.x把 MyBatis Plus 依赖换成dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-spring-boot3-starter/artifactId version3.5.5/version /dependency重点说一下达梦驱动。DmJdbcDriver18这个 jar 很多时候不在公共 Maven 仓库里你需要去达梦官网或者数据库安装目录的drivers/jdbc目录下找找到后手动安装到本地仓库mvn install:install-file -DfileDmJdbcDriver18.jar -DgroupIdcom.dameng \ -DartifactIdDmJdbcDriver18 -Dversion8.1.2.192 -Dpackagingjar如果团队用私有 Nexus直接上传到私服避免每个人本地装一遍。另外驱动 jar 名字里的 18 不是数据库版本而是 JDBC 规范版本JDK 8 和 JDK 17 都能用 DmJdbcDriver18JDK 1.6 那种老环境才需要去找 DmJdbcDriver16。2.2 application.yml 里的数据源配置driverClassName 是第一个坑达梦的驱动类名是dm.jdbc.driver.DmDriver不是com.mysql.cj.jdbc.Driver。配置如下spring: datasource: driver-class-name: dm.jdbc.driver.DmDriver url: jdbc:dm://127.0.0.1:5236 username: SYSDBA password: SYSDBA001 hikari: minimum-idle: 5 maximum-pool-size: 20 connection-timeout: 30000这里有两个容易踩的点。第一URL 默认写jdbc:dm://127.0.0.1:5236就可以不需要像 MySQL 那样带库名如果你的实例配置了服务名可以在端口后加/服务名但大多数情况下不加更稳。第二达梦驱动对 URL 上的一些参数是能认的但对 MySQL 的那套useSSL、serverTimezone完全不认加上去反而可能让连接失败。有人喜欢在这里加?useUnicodetruecharacterEncodingUTF-8实际测试中达梦驱动对字符编码的处理主要看数据库实例的字符集URL 参数不是必须的反而可能因为参数不识别导致问题。真遇到乱码先查数据库字符集和客户端的编码环境变量。2.3 MyBatis Plus 方言配置和分页拦截器必须显式写 DbType.DMMyBatis Plus 3.5.5 已经内置了达梦方言分页插件里可以直接指定DbType.DM。这个配置要单独建一个配置类并且确保被 Spring Boot 扫描到Configuration MapperScan(com.example.mapper) public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); PaginationInnerInterceptor paginationInnerInterceptor new PaginationInnerInterceptor(DbType.DM); // 分页数量限制按实际业务设置不需要限制就保持默认 paginationInnerInterceptor.setMaxLimit(500L); // 超出总数时自动回退到最后一页 paginationInnerInterceptor.setOverflow(true); interceptor.addInnerInterceptor(paginationInnerInterceptor); return interceptor; } }很多“分页失效”问题的根因就是这个拦截器没配置。如果拦截器缺失MyBatis Plus 会走内存分页甚至直接报错。拦截器配了但分页方言用错也会导致 SQL 生成不符合达梦语法。所以这里建议无论你数据库实例用的是哪种兼容模式代码里都统一用DbType.DM让 MyBatis Plus 自己处理达梦方言不要去猜它是不是兼容 MySQL。3. 实体映射和建表规范把 MySQL 思维切到达梦习惯3.1 表名、字段名大小写与保留字SQL 异常的常见来源从 MySQL 迁到达梦保留字问题几乎必然遇到。MySQL 里可以利用反引号把order、group、user这样的字段包起来但达梦对反引号的支持要看兼容模式不是所有模式都认。达梦的保留字体系和 Oracle 更接近COMMENT、OPTION、CONDITION、LEVEL、ROWNUM、SIZE、VALUE、USER这些词在 SQL 里出现时都有被解析成关键字的风险。保险做法是两点建表字段尽量避开保留字从源头解决。如果老表已经建成这样实体里用TableField显式转义TableName(T_USER) public class User { TableId(value ID, type IdType.AUTO) private Long id; TableField(USER_NAME) private String userName; // OPTION 是保留字必须加双引号 TableField(\OPTION\) private String option; }注意这里用的是双引号不是 MySQL 习惯的反引号。达梦在解析带双引号的标识符时对大小写是敏感的如果你建表时写的是OPTION那表里存储的列名就是大写如果建表时没加引号达梦默认也会转成大写存储。所以代码里统一按大写写配合TableField的双引号转义基本不会出错。3.2 主键策略IDENTITY、ASSIGN_ID 和达梦自增列的关系MyBatis Plus 默认主键策略是ASSIGN_ID也就是应用侧生成雪花 ID这个策略在达梦上最省事因为它不依赖数据库自增机制。从 MySQL 迁过来的项目如果原来主键是bigint auto_increment在达梦里建表要用类似这样的语法CREATE TABLE T_USER ( ID BIGINT IDENTITY(1,1), USER_NAME VARCHAR(64), OPTION VARCHAR(128), PRIMARY KEY (ID) );这时实体里的TableId(type IdType.AUTO)才能配合数据库自增。如果你的迁移工具把自增列映射成了普通BIGINT但代码里又写成IdType.AUTO插入的时候就会报错或者主键为 NULL。迁完后别急着跑业务先对着表结构检查几张大表的主键是否真的是自增列。生产环境里老数据主键往往不能乱变如果主键由业务系统生成建议直接在实体上标注IdType.INPUT不要让它走默认的雪花策略否则会出现插入的数据主键和外部系统对不上。3.3 类型映射检查清单这些字段迁移后最容易出问题达梦的数据类型体系比 MySQL 更复杂迁移工具虽然能帮你做映射但映射完不等于能用。我整理过一份需要人工复查的类型清单MySQL 类型达梦常用类型注意点tinyint / int / bigintINT / BIGINT / NUMBER长度和自增属性要核对datetimeTIMESTAMP达梦 DATE 也带时间但要看你建表时的具体类型textTEXT / CLOBCLOB 在 XML 查询里的一些比较操作有限制varchar(n)VARCHAR(n)达梦 VARCHAR 长度默认按字节还是字符要确认会影响中文长度decimalNUMERIC / NUMBER精度位数要核对避免金额字段被截断bit / booleanBIT / INT达梦没有完全等价的 boolean 语义通常用 INT 0/1迁移完数据后我的建议是写一段“类型冒烟测试”把每张表的字段都查一遍用SELECT COUNT(1) WHERE 字段 IS NOT NULL之类的方式扫一遍至少能发现隐式转换和长度截断的问题。真遇到异常优先改表字段类型不要在 XML 里写一堆CAST那个维护成本太高。4. 分页问题的完整排查链路从“列表翻页异常”到定位根因4.1 现象总数不对、翻页超过某条数就报错、单页 500 条之后行为反常迁移过程中最有意思的是分页问题。最初项目里几个列表接口的表现很怪前几页正常后面越翻越不对劲有的接口返回总数和 count 总数不一致还有一页查 500 条以内没问题超过 500 条就报 SQL 错误。搜索“mybatisplus单页500条限制”“mybatisplus分页失效”的相关信息基本都是在达梦或类似国产数据库上遇到的。在动手改代码之前我先确认了一件事分页插件到底有没有生效如果没生效MyBatis Plus 的Page对象虽然能接住数据但底层执行的是不带分页的原始 SQL然后IPage在内存里做截断。这种模式下业务看结果是“有数据的”但总数不准、页数越界且数据量大了以后非常慢。4.2 排查第一步让 MyBatis Plus 把真实 SQL 打到控制台像这种诡异问题不要猜直接看 SQL。我建议在测试环境把 MyBatis Plus 的日志打开mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl这时候控制台会把 MyBatis Plus 生成并执行的 SQL 完整打出来包括分页插件拼接后的语句和参数列表。拿到完整 SQL 之后复制到 DBeaver 或 DM 管理工具里手工跑一遍看看到底是达梦解析不了还是返回结果本身有问题。4.3 排查第二步检查分页拦截器的配置和版本日志确认 SQL 只是普通查询、完全没带分页关键字时问题基本就是PaginationInnerInterceptor没注册。这种情况通常有两种原因一是配置类被 Spring Boot 的组件扫描漏掉了二是项目里改了自定义拦截器分页拦截器没加进去。另一种情况是 SQL 里带LIMIT但达梦报语法错误。这就要回溯到数据库初始化时的兼容模式了。如果你的达梦实例跑在 Oracle 兼容模式下MySQL 风格的LIMIT offset, size不一定被支持而旧版 MyBatis Plus 里如果你强行用DbType.MYSQL生成分页 SQL很可能生成的就是这种语法。我的配置方案是统一使用 MyBatis Plus 3.5.5 以上的版本并且在拦截器里显式写DbType.DM。这个方言类会根据达梦支持的语法生成分页语句比手动指定 MySQL 稳妥得多。4.4 修复后的标准配置和验证建议修复完配置之后不要只点两下页面就觉得完事了我建议验证这几项分别用第 1 页、中间页、最后一页调用接口检查total、pages、current、size是否正确。在调用接口时同时打印 count 查询 SQL 和数据查询 SQL确认 count 语句没有分页关键字数据语句有达梦风格的分页语法。如果设置了setMaxLimit(500L)那么单页 size 大于 500 时会被拦截或报错你自己要清楚这是业务限制而不是数据库 bug如果你没设置过却出现 500 条上限大概率是项目里有人加过配置直接全局搜maxLimit就能找到。我之前在排查中看到的“单页500条限制”现象最后发现不是达梦数据库本身强制的而是项目早期接入时有人在分页拦截器里配了setMaxLimit(500L)。这个配置是会真实生效的超过 500 的查询可能被直接修正或报异常所以遇到类似情况时先在代码仓库里搜一下maxLimit别一上来就怀疑数据库。5. 批量操作、事务边界和 SQL 日志的落地姿势5.1 saveBatch 到达梦之后的性能变化别期望和 MySQL 一样MyBatis Plus 的IService.saveBatch()在 MySQL 上表现不错但在达梦上不一定。原因是 MySQL 驱动支持rewriteBatchedStatementstrue时会把批量插入重写成多 VALUES 语句达梦驱动的批处理行为不完全相同而且我的测试里同样一批数据在达梦上逐条执行的比例更高插入耗时明显增加。如果是偶发的小批量操作直接用saveBatch问题不大如果是定时任务、数据导入这种批量插入量大的场景建议自己写 XML 里的批量插入insert idbatchInsert parameterTypelist INSERT INTO T_USER(ID, USER_NAME, OPTION) VALUES foreach collectionlist itemitem separator, (#{item.id}, #{item.userName}, #{item.option}) /foreach /insert注意控制批次大小我一般控制在 200 到 500 条一批避免 SQL 过长超出达梦的参数上限或者触发事务日志暴涨。全量导入数据时还可以关闭自动提交分批次手动 commit。5.2 事务边界与默认隔离级别Transactional 的默认行为要小心达梦默认的隔离级别是读提交和 MySQL 默认的可重复读不一样但我们的业务里多数场景读提交反而够用。集成时更需要注意的是 Spring 事务的语义Transactional(rollbackFor Exception.class) public void doSomething() { // 业务逻辑 }一定不要只写Transactional不指定rollbackFor。Spring 默认只对RuntimeException和Error回滚如果你在事务里抛了一个自定义的受检异常事务不会回滚数据库里会留下半截数据。这在 MySQL 时代也是这个规则但达梦侧排查起来会更隐蔽因为日志里看不到明显报错。还有一个经验不要把长报表查询、大数据量导出放在Transactional里去跑。达梦的事务开销和 Oracle 类似长事务会拖住 undo 空间和锁批量操作和查询之间要严格分开。如果只是查询直接不要加事务注解让连接自动提交就好。5.3 打开 SQL 日志用达梦工具复现执行前面提到的 SQL 日志配置除了排错还有一个重要用途让你能随时把 MyBatis Plus 生成的 SQL 复制到数据库工具里验证。这一点在达梦上尤其重要因为达梦没有 MySQL 那么丰富的在线调试生态很多问题只能靠“拿真实 SQL 去管理工具里重新执行”来确认。但生产环境一定不要开StdOutImpl它会把 SQL 里的参数值全部打到日志文件里可能包含用户手机号、身份证号之类的敏感数据。生产需要慢 SQL 分析时可以通过数据库层面的 SQL 日志或者监控平台来做应用侧只保留异常 SQL 的输出。6. DBeaver、Navicat、达梦管理工具的连接和配合方式6.1 DBeaver 手动注册达梦驱动新版 DBeaver 部分版本内置了达梦驱动但如果没有手动添加也不复杂下载DmJdbcDriver18.jar。在 DBeaver 菜单里选择“数据库” - “驱动管理器” - “新建”。驱动名称填DM驱动类填dm.jdbc.driver.DmDriver。URL 模板填jdbc:dm://{host}:{port}。在“库”区域添加下载好的 jar 包。新建连接主机填数据库 IP端口填 5236用户名密码填达梦账号。DBeaver 连接达梦最常见的坑是端口写错或者驱动 jar 和数据库版本不对应。如果测试连接报“未找到驱动类”先确认 jar 是否真的被 DBeaver 加载进去了。6.2 Navicat 和达梦管理工具的配合Navicat 连接达梦需要用支持达梦的版本新建连接时选择达梦数据库类型连接参数和 DBeaver 基本一致IP、端口 5236、用户名、密码。如果你的 Navicat 版本较旧新建连接列表里没有达梦那就换 DBeaver 或者达梦自带的 DM 管理工具没必要纠结。达梦自带管理工具连接上之后最容易被新手卡住的是“看不到表”。默认用 SYSDBA 登录后左侧对象导航栏展开的是当前用户模式如果你要看的表在业务模式比如APPUSER下那需要在导航栏上方的模式下拉框里选到APPUSER模式表才会出现。如果整个对象导航栏都不显示检查菜单栏里的视图开关不要误以为数据库里没表。6.3 迁移验证阶段的数据准备和备份恢复为了不影响生产迁移验证阶段我会先在一台独立环境里把达梦库搭好然后用达梦的数据迁移工具 DTS 把 MySQL 的表结构和数据导过来。备份和还原用达梦的逻辑导入导出命令就可以dexp USERIDSYSDBA/SYSDBAlocalhost:5236 FILEbackup.dmp FULLYdimp USERIDSYSDBA/SYSDBAlocalhost:5236 FILEbackup.dmp FULLY当然生产环境建议用达梦的物理备份工具这里只是说测试验证阶段用逻辑备份最快。还原 dmp 文件时如果目标库里的模式不存在可以先手工建好同名用户/模式再用dimp导入避免还原一半报用户名不存在。另一件容易被忽略的事迁移完数据后先跑一轮 MyBatis Plus 的 Mapper 方法自测把每个实体对应的selectPage、selectList、insert、updateById都执行一遍重点观察有没有保留字、类型转换、主键冲突这几类问题。这种“全量扫 Mapper”看起来笨但确实能提前暴露大部分兼容性问题比业务侧手工点流程要高效得多。最后再分享一个实际体会在把 Spring Boot 项目切到达梦数据库这类国产数据库上时最大的成本不是写代码而是把团队里“一直默认是 MySQL”的隐性假设全部翻出来。分页方言、主键自增、字段保留字、批量插入、事务语义每一项都要单独验证。把前面这些检查点过完安装、编码、部署这套流程基本就能稳定重复了之后再有新人加入照着这份事项清单走不会一头扎进“为什么数据库查不了第二页”的坑里。
返回列表