多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

达梦数据库SQL高频写法与避坑实战总结

达梦数据库SQL高频写法与避坑实战总结 最近在做信创项目把一套跑了七八年的Oracle系统整体迁移到达梦数据库同时也有几个新项目直接落在达梦上。这段时间写SQL、调SQL、排查连接问题的频率非常高我把日常用到的高频SQL和踩过的坑整理成一篇总结给正在接触达梦数据库的朋友做参考。这份总结不会只列“标准答案”而是把达梦数据库和Oracle、MySQL的差异点、容易报错的地方、以及实际项目中验证过可行的写法一起讲清楚。如果你是第一次用达梦数据库的开发者或DBA这篇内容能帮你少走很多弯路如果你已经在用达梦也可以对照看看有没有遗漏的细节。达梦的SQL整体兼容性做得不错但“兼容”不等于“完全一样”真正上手后你会发现很多报错都藏在细节里。1. 达梦数据库的SQL体系与三个先决认知1.1 兼容模式Oracle语法和MySQL语法都认但有个前提达梦数据库是国内做得比较早的国产关系型数据库它的SQL语法体系设计上走的是“多兼容”路线。也就是说你既可以用Oracle风格写SQL也可以用MySQL风格写SQL具体由数据库实例的初始化参数决定。最核心的参数是COMPATIBLE_MODE它决定了数据库在语法解析、函数行为、分页写法上更偏向哪一边。这个参数在初始化实例的时候配置后面一般不会去改。实测下来大多数政企项目初始化达梦时用的是Oracle兼容模式因为历史系统基本都是Oracle迁过来的业务代码里Oracle痕迹太重。如果你的环境是MySQL迁过来的那初始化时就要明确指定兼容MySQL。这里有个很实际的影响分页SQL写法、字符串拼接符号、部分日期函数在两种模式下行为不一样。我在项目中常用的判断方法很简单执行一句SELECT * FROM v$parameter WHERE name COMPATIBLE_MODE;看返回的取值是几。0表示Oracle兼容1表示MySQL兼容2表示部分兼容。带着这个认知去写SQL很多“为什么我这么写报错、那么写不报错”的疑惑就能解释通了。1.2 大小写敏感这是新手最容易“莫名其妙”报错的地方达梦数据库默认行为和Oracle一致未加双引号的标识符一律转换为大写存储和解析。这句话你要是忽略了后面会有大量“无效的表名”、“无效的列名”报错在等你。举个真实例子。开发同事在客户端里执行CREATE TABLE user_info ( id INT, user_name VARCHAR(50) );执行成功看着没问题。然后查询时他写SELECT user_name FROM user_info;结果报“无效的表名或视图名”。原因是他用的客户端工具如果设置了保留小写或者他创建时实际生成的是大写标识符两条语句对不上。达梦在未加双引号的情况下把user_info理解为USER_INFO而表实际是以什么名字存储的取决于创建时的行为。实际操作中我一般建议团队统一约束建表语句全部用大写或者全部加双引号并保持大小写一致。尤其从MySQL迁过来的兄弟MySQL里小写习惯太深到了达梦很容易在这里翻车。如果你不确定某个对象的实际存储名称可以查系统视图SELECT OBJECT_NAME, OBJECT_TYPE FROM ALL_OBJECTS WHERE OBJECT_TYPE TABLE;看到实际名字再决定SQL怎么写比在那里干猜快得多。1.3 模式SCHEMA达梦里的“模式错误”一半和它有关达梦的模式概念和用户关系紧密。默认情况下每个用户会对应一个同名的模式。如果没有显式指定你登录后创建的表、视图都放在当前用户对应的模式里。跨模式访问必须带模式名前缀模式名.表名。热词里有“达梦数据库 模式错误”我排查过好几个这样的问题原因大同小异A用户创建了表B用户去查直接写SELECT * FROM table_name结果报“无效的表名”或“模式不存在”。因为在B用户的默认模式下根本没这个表。正确写法是加上模式名。比如你登录的是SYSDBA但表建在TEST模式下SELECT * FROM TEST.USER_INFO;还有一种情况更隐蔽应用配置里连接的用户名是AJDBC URL里没加schema属性但业务SQL里全是B模式下的表导致应用一启动就各种表找不到。解决办法要么给SQL全加上模式名前缀要么在连接层面指定默认模式。比如JDBC URL里可以加schemaxxxDruid数据源里也有对应的配置项。理解用户、模式、表这三层关系你就能少走至少一半弯路。记住一句话先确认你在哪个模式再确认表在哪个模式最后再写SQL。2. 高频基础SQL写法与避坑要点2.1 建表与自增主键IDENTITY还是序列达梦建表语法整体跟Oracle像但自增列的处理和MySQL、SQL Server更像。常用两种方案一种是使用IDENTITY自增列一种是使用序列(SEQUENCE)配合默认值或触发器。先看IDENTITY的写法CREATE TABLE USER_INFO ( ID INT IDENTITY(1,1) PRIMARY KEY, USER_NAME VARCHAR(50), CREATE_TIME DATETIME DEFAULT SYSDATE );这里IDENTITY(1,1)表示从1开始每次递增1。插入数据时不要手动给ID赋值让它自己生成INSERT INTO USER_INFO (USER_NAME, CREATE_TIME) VALUES (张三, SYSDATE);序列的写法则更Oracle一些CREATE SEQUENCE SEQ_USER_INFO_ID START WITH 1 INCREMENT BY 1;插入时使用序列INSERT INTO USER_INFO (ID, USER_NAME, CREATE_TIME) VALUES (SEQ_USER_INFO_ID.NEXTVAL, 张三, SYSDATE);这两种方式在达梦里都支持。如果项目是从Oracle迁过来的用序列方式改动最小如果是从MySQL迁过来的IDENTITY方式更顺手。需要注意的坑达梦表字段类型里MySQL习惯的VARCHAR没问题但Oracle习惯的VARCHAR2达梦也兼容。日期类型用DATE、DATETIME、TIMESTAMP按精度需求选择。大字段用CLOB或TEXT实际迁移时我见过有人直接把MySQL的LONGTEXT搬过来达梦也能兼容但建议在表结构确认时顺手规范掉。2.2 增删改查与NULL的判断千万别用“ NULL”增删改查是数据库使用频率最高的一类SQL但是简单的语句里也有容易翻车的地方。先说查询过滤-- 正确写法判断NULL SELECT * FROM USER_INFO WHERE USER_NAME IS NULL; -- 错误写法 NULL 永远不返回结果 SELECT * FROM USER_INFO WHERE USER_NAME NULL;这几乎是所有SQL新手都会踩的坑。在SQL标准里NULL代表未知值任何用或与NULL比较的结果都是“未知”最终不返回任何行。达梦也一样这个习惯要刻在脑子里。再说UPDATE和DELETE这两类语句在生产环境一定要养成先查后改的习惯-- 先确认要影响哪些行 SELECT * FROM USER_INFO WHERE ID 100; -- 再执行更新 UPDATE USER_INFO SET USER_NAME 李四 WHERE ID 100; -- 删除前也先看一眼 DELETE FROM USER_INFO WHERE ID 100;还有一个场景批量更新时达梦的MERGE INTO语法很好用尤其是做数据同步的时候。达梦完全支持Oracle的MERGE写法MERGE INTO USER_INFO T USING (SELECT 100 AS ID, 王五 AS USER_NAME FROM DUAL) S ON (T.ID S.ID) WHEN MATCHED THEN UPDATE SET T.USER_NAME S.USER_NAME WHEN NOT MATCHED THEN INSERT (ID, USER_NAME) VALUES (S.ID, S.USER_NAME);这个写法在从外部表或临时表同步数据时极其高效避免了先Select判断再Update或Insert的繁琐流程。2.3 去重的三种姿势DISTINCT、GROUP BY、窗口函数去重是热词里出现频率很高的需求。按我的经验不同场景用不同姿势别一味只会DISTINCT。最简单的是单表多列去重SELECT DISTINCT USER_NAME, DEPT_ID FROM USER_INFO;但当你想把去重后的行里的其他字段也查询出来时DISTINCT就不够用了。比如我想查每个用户最新的联系方式正确姿势是用窗口函数SELECT * FROM ( SELECT T.*, ROW_NUMBER() OVER(PARTITION BY USER_NAME ORDER BY CREATE_TIME DESC) RN FROM USER_INFO T ) WHERE RN 1;基于去重需求分组聚合是另一种常用姿势SELECT DEPT_ID, COUNT(*) AS USER_CNT, MAX(CREATE_TIME) AS LAST_TIME FROM USER_INFO GROUP BY DEPT_ID;注意坑点达梦对GROUP BY的字段要求比MySQL严格SELECT中出现的非聚合列必须出现在GROUP BY中。这个就是从Oracle带过来的习惯从MySQL迁移过来的项目需要适应一下。2.4 分页查询三种写法在达梦里并存达梦分页是个特色场景因为兼容模式不同支持多种写法。我按项目经验给你列出来用哪种取决于你们的代码规范和迁移成本。第一种Oracle风格的分页用ROWNUM伪列SELECT * FROM ( SELECT T.*, ROWNUM RN FROM (SELECT * FROM USER_INFO ORDER BY ID) T WHERE ROWNUM 20 ) WHERE RN 10;这种写法相对繁琐但Oracle迁移项目里经常会见到。第二种MySQL风格的LIMITSELECT * FROM USER_INFO ORDER BY ID LIMIT 10, 20;注意LIMIT的语义MySQL习惯LIMIT 偏移量, 行数达梦也兼容这个用法。如果你在MySQL兼容模式下初始化这种写法最省事。第三种TOP 子查询SELECT TOP 10 * FROM USER_INFO;适合只取前几条的场景分页时配合子查询也能做。我的建议新项目直接统一用LIMIT写法定规范简单直观。迁移项目保持原有Oracle写法改动最小。但要注意在Oracle兼容模式下LIMIT是否能直接用取决于达梦版本和初始化参数我建议先在本机执行一句SELECT * FROM USER_INFO LIMIT 1验证一下能跑通就放心用跑不通就老老实实ROWNUM。2.5 空值处理NVL、COALESCE怎么选空值处理在SQL里无处不在。达梦支持Oracle的NVL也支持SQL标准的COALESCE。日常使用时我按场景选择-- NVL两个参数第一个为NULL时返回第二个 SELECT NVL(USER_NAME, 未知用户) FROM USER_INFO; -- COALESCE可以多个参数从左到右取第一个非NULL值 SELECT COALESCE(PHONE, EMAIL, 无联系方式) FROM USER_INFO;如果只有两个值的兜底判断用NVL多个字段“哪个有值用哪个”的场景用COALESCE灵活得多。还有一个NULLIF当两个值相等时返回NULL。比如查一个表中某个指标是否为0写NULLIF(AMOUNT, 0)配合聚合函数就能把0值排除出统计范围。3. 进阶SQL函数、窗口函数、序列3.1 字符串处理的细节判断数字字符串的三种思路热词里有一条“db2 sql判断数字字符串函数”不同数据库实现不同。在达梦里判断某个字段是否由纯数字组成我常用三种方式第一种用REGEXP_LIKE正则判断最直观SELECT USER_NAME FROM USER_INFO WHERE REGEXP_LIKE(USER_NAME, ^[0-9]$);第二种用TRANSLATE函数替换掉数字字符看结果是否为NULL或空串SELECT USER_NAME FROM USER_INFO WHERE TRANSLATE(USER_NAME, 0123456789, ) IS NULL;第三种利用数据转换报错的方式不可控不建议在SQL里直接CAST因为遇到非法字符会直接报错中断整个查询。字符串处理的其他常用函数达梦和Oracle基本一致LENGTH获取长度SUBSTR截取子串REPLACE替换INSTR查找位置。注意字符串连接符号Oracle兼容模式下用||SELECT USER_NAME || - || DEPT_NAME FROM USER_INFO;MySQL兼容模式下也可以使用CONCAT(USER_NAME, - , DEPT_NAME)。为了统一我会在项目里指定一种风格避免两种写法混用。3.2 日期时间函数SYSDATE、TO_DATE和相关计算达梦的日期函数体系相当完整。当前日期时间的获取SYSDATE和CURRENT_TIMESTAMP都可用。字符串转日期用TO_DATESELECT TO_DATE(2025-06-01 12:00:00, YYYY-MM-DD HH24:MI:SS) FROM DUAL;日期差值计算可以用DATEDIFFSELECT DATEDIFF(DAY, CREATE_TIME, SYSDATE) AS DAYS_OLD FROM USER_INFO;也可以使用DATEADD做日期的偏移计算SELECT DATEADD(MONTH, -6, SYSDATE) FROM DUAL;按年月日做聚合统计时用EXTRACT抽取日期分量SELECT EXTRACT(YEAR FROM CREATE_TIME) AS Y, EXTRACT(MONTH FROM CREATE_TIME) AS M, COUNT(*) FROM USER_INFO GROUP BY EXTRACT(YEAR FROM CREATE_TIME), EXTRACT(MONTH FROM CREATE_TIME);特别注意字符串日期比较时千万别依赖隐式转换。字段是VARCHAR存了2025-06-01你把条件写WHERE date_str TO_DATE(2025-06-01, YYYY-MM-DD)两边类型不一致要么报错要么走不了索引。正确做法是同一类型互比字段如果是日期类型就用日期和它比字段如果是字符串类型就用字符串格式和它比保持格式统一例如WHERE date_str 2025-06-01。3.3 窗口函数ROW_NUMBER、RANK、DENSE_RANK的应用窗口函数是处理“分组取TopN”“同组内排名”这类问题的标准答案达梦对窗口函数的支持已经比较完整。分组取每个部门最新入职的两个人SELECT * FROM ( SELECT E.*, ROW_NUMBER() OVER(PARTITION BY DEPT_ID ORDER BY HIRE_DATE DESC) RN FROM EMPLOYEE E ) WHERE RN 2;排名时RANK和DENSE_RANK在并列排名时行为不同。RANK遇到并列会跳过排名号比如两个并列第二下一个就是第四DENSE_RANK则不跳号下一个是第三。按业务需求选择。聚合窗口函数也很好用比如算累计值SELECT DEPT_ID, AMOUNT, SUM(AMOUNT) OVER(PARTITION BY DEPT_ID ORDER BY CREATE_TIME) AS CUM_AMOUNT FROM SALES;这个写法的含义是“同一部门内按时间累加金额”比在程序里循环快得多也便于后续做趋势分析。3.4 序列与自增值处理NEXTVAL和CURRVAL的正确用法前面建表部分提到过序列。这里补充几个使用细节。序列取值用.NEXTVAL和.CURRVAL-- 获取下一个值 SELECT SEQ_USER_INFO_ID.NEXTVAL FROM DUAL; -- 获取当前值必须在本会话中已经至少执行过一次NEXTVAL才能用 SELECT SEQ_USER_INFO_ID.CURRVAL FROM DUAL;在实际项目中很多场景不一定要把序列直接绑到表的默认值上而是业务代码里先取一个序列值再作为主键插入。这种方式对分布式应用也友好避免依赖数据库的自增机制。批量插入时如果需要一组连续ID可以先循环取序列值再拼接语句。但要注意序列是“取一次跳一次”就算事务回滚了已取出的序列值也不会归还。这个特性跟Oracle完全一样别指望回滚后序列值能连续。达梦的序列缓存大小也是可以配置的高并发环境下适当调大CACHE可以减少性能损耗。4. 慢SQL排查与优化实操4.1 先看执行计划EXPLAIN是优化第一步SQL写得再花哨最终还是要看执行计划来判断好坏。达梦里用EXPLAIN关键字可以查看一条SQL的执行计划EXPLAIN SELECT * FROM USER_INFO WHERE DEPT_ID 10;输出里重点看几类信息访问方式是全表扫描 TABLE ACCESS FULL还是索引扫描 INDEX RANGE SCAN、连接顺序先连哪张表再连哪张表、连接方式嵌套循环、哈希连接、排序合并。全表扫描在大表查询中往往是性能瓶颈的头号嫌疑。如果需要更详细的统计信息和实际执行代价可以在达梦管理工具或通过EXPLAIN WITH STATISTICS之类的扩展方式看执行过程。平时调优我的顺序是先看执行计划有没有全表扫描再看过滤条件有没有走到索引最后看排序和连接是否有优化空间。4.2 索引的建立原则不是建得越多越好达梦的索引类型和Oracle大体一致B树索引是默认主力。建立索引时我遵循这么几条原则等值查询频繁的字段放最前面范围查询字段放后面这是复合索引“最左前缀”的原则。尽量用区分度高的字段做索引比如用户ID、订单号。性别这种区分度极低的字段建索引收益很小反而增加写入开销。复合索引列数量建议控制在3列以内不是越多越好。WHERE条件中的字段如果有函数包裹比如WHERE UPPER(USER_NAME) ZHANG普通索引会失效这时候要考虑建函数索引。达梦支持函数索引这是一个容易被忽视但有奇效的功能CREATE INDEX IDX_USER_INFO_UNAME ON USER_INFO(UPPER(USER_NAME));在从MySQL迁到达梦的项目里函数索引尤其有用因为很多业务SQL习惯在查询条件里写各种函数。4.3 并行查询和绑定变量大表和重复SQL的两种解法统计大表、跑历史报表时合理使用并行查询能显著缩短耗时。达梦支持PARALLEL提示语法和Oracle类似SELECT /* PARALLEL(4) */ COUNT(*) FROM BIG_SALES_TABLE;但并行不是万能的并发高的小事务场景开并行反而是负担。我的经验是只有单条大查询、数据量超过千万级、服务器CPU有富余时才考虑用并行。另一个容易被忽略的点是绑定变量。如果应用层不断提交结构相同、只是条件值不同的SQL达梦每次都要做硬解析对CPU和共享池都是压力。MyBatis里默认使用#{}占位符就能自动走绑定变量在达梦上实测有效。顺便说一句${}拼接方式除了有SQL注入风险也会导致执行计划无法复用能不用就不用。4.4 常见慢SQL场景与改写思路我总结项目中高频出现的三类慢SQL以及相应的改写方向。第一类OR条件导致索引失效。例如SELECT * FROM ORDERS WHERE STATUS 1 OR STATUS 2;这种可以改写成UNION ALLSELECT * FROM ORDERS WHERE STATUS 1 UNION ALL SELECT * FROM ORDERS WHERE STATUS 2;第二类LIKE %关键字%前置模糊匹配索引走不上。好一点的做法是全文索引或者把查询条件改成前缀匹配LIKE 关键字%。如果业务必须前后模糊查数据量大时建议上搜索组件或者接受全表扫描的事实。第三类大偏移量分页LIMIT 100000, 20要扫描前面10万行才能取到数据。优化思路是“先取ID再回表查详情”SELECT * FROM ORDERS WHERE ID (SELECT ID FROM ORDERS ORDER BY ID LIMIT 100000, 1) ORDER BY ID LIMIT 20;这种写法利用主键索引直接跳到目标位置附近比直接LIMIT大偏移高效得多。5. 达梦数据库连接与常见报错排查5.1 驱动、端口与JDBC URL这些参数别写错达梦的JDBC驱动类名是dm.jdbc.driver.DmDriver默认端口是5236和MySQL的3306、Oracle的1521都不一样项目配置时容易写错。JDBC URL的标准格式jdbc:dm://127.0.0.1:5236?schemaTEST注意最后的schemaTEST参数可以用来指定默认模式。如果应用里很多业务表都建在TEST模式下URL里带上这个参数能省掉很多麻烦。驱动JAR包在达梦数据库安装目录的drivers/jdbc下有对应文件比如DmJdbcDriver18.jar。使用Maven时达梦驱动一般不在中央仓库需要用install-file命令打到本地仓库或者私服里单独上传。5.2 Navicat和IDEA连接达梦的实操Navicat连接达梦需要 Navicat Premium 16 及以上版本连接类型里选择“达梦数据库”。填主机、端口、用户名、密码测试连接通过即可。这里有个细节Navicat连接达梦时如果你选择的连接类型不对会一直提示“无法加载驱动”先确认版本够新再看驱动有没有装上。IDEA连接达梦比Navicat稍微麻烦一点。在IDEA的Database面板里新建数据源时如果列表里没有达梦需要手动添加驱动。做法是在数据源配置界面选择“驱动”Tab添加一个驱动类驱动库文件指向你本地下载的DmJdbcDriver.jar类名填dm.jdbc.driver.DmDriverURL模板填jdbc:dm://host:port。然后把驱动配置到数据源里填好账号密码就能连上。5.3 常见报错速查表这里把我在项目中遇到过的达梦SQL相关报错和解决思路整理成一张速查表方便对照排查。报错信息常见原因解决思路无效的表名或视图名表名大小写不一致或没有加模式名用大写标识符或查询ALL_OBJECTS确认实际表名跨模式加前缀无效的列名SELECT或WHERE中的列名与表结构不一致确认列名大小写和所属表注意达梦未加双引号后转大写模式不存在连接用户下没有对应模式确认初始化时的模式名SQL中加模式名.表名字符串截断插入的数据长度超出字段定义检查VARCHAR长度定义必要时改用CLOB或TEXT仅支持指定级别的空值空值比较语法错误改用IS NULL/IS NOT NULL不用 NULL锁等待超时事务未提交其他会话阻塞排查ACTIVE事务提交或回滚调整锁超时配置非法的数字字符串转数字失败先清理脏数据或用REGEXP_LIKE过滤非数字内容后再转换5.4 锁等待和事务问题一条SQL卡住别慌达梦的锁等待机制和Oracle总体类似。一个会话更新了某行但没提交其他会话更新同一行时就会阻塞。排查时可以用达梦的动态视图查询锁信息比如SELECT * FROM V$LOCK;再看哪些事务占用了资源、持有了多久。日常反复出现锁等待的项目我会重点关注两件事一是代码里事务是不是开得太久有没有在事务里做了大量耗时的外部调用二是连接池连接的数量和获取等待时间是否合理。另外一个经验遇到“锁等待超时”不是简单调大超时时间就够了超时时间调太大只会掩盖问题。真正要做的是找到没提交的事务源头把事务逻辑改短改小避免大事务长时间持有锁。6. 达梦与SpringBoot/MyBatis集成时的SQL兼容性细节6.1 Druid数据源配置达梦的几个关键点SpringBoot项目最常用的组合是 MyBatis Druid 数据库。切到达梦后Druid数据源配置里需要指定达梦驱动spring: datasource: driver-class-name: dm.jdbc.driver.DmDriver url: jdbc:dm://127.0.0.1:5236?schemaTEST username: TEST password: test123 druid: validation-query: SELECT 1validation-query: SELECT 1这一行很重要。Druid默认的校验SQL可能是SELECT 1 FROM DUAL在达梦里虽然也能跑但换成SELECT 1更通用避免某些兼容模式下不必要的报错。还要注意Druid的filters配置如果有wall防火墙过滤器有些达梦语法可能被误拦截比如LIMIT、MERGE INTO。遇到“SQL被拦截”的报错可以把wall过滤器去掉或调整白名单。6.2 从Oracle迁移到达梦SQL的兼容性比对迁移项目最大的痛点是SQL方言。Oracle和达梦虽然是血缘关系最近的一对但仍有细节差异。我遇到过的最常见几个ROWNUM分页在达梦里能用但如果涉及子查询嵌套的复杂分页建议直接用窗口函数或LIMIT重写逻辑更清晰。DECODE函数在达梦里也支持但嵌套过多时可读性差建议改成CASE WHEN两边都兼容且更易维护。SYSDATE两边一致没问题。但SYSTIMESTAMP的精度差异要注意涉及时间戳精确到微秒的业务要在联调时验证。自增列Oracle的GENERATED BY DEFAULT AS IDENTITY达梦也有类似语法但如果Oracle侧是用SEQUENCE TRIGGER实现的迁移到达梦建议直接用达梦的IDENTITY。字符串类型Oracle的VARCHAR2(20)达梦能用但如果代码里有VARCHAR2(20 CHAR)这样的字符长度语义注意达梦对字符和字节的处理要与源库核对避免字段长度不够截断。我在迁移时给团队定了条规矩所有SQL先在一个统一的兼容模式测试库上跑一遍再上测试环境联调。达梦的兼容性总体出色但“绝大多数”不是“百分之百”你必须用你自己的SQL去试。6.3 MyBatis XML里的SQL写法建议写MyBatis的XML文件时有几个习惯可以有效减少达梦兼容性问题。用#{}传参不要用${}拼接。前面说了既能预防SQL注入又能让达梦走绑定变量复用执行计划。分页插件如果用PageHelper需要给达梦配置对应的方言。PageHelper官方支持达梦配置一下dialect: dm就行。如果项目里是自己手写的分页用LIMIT #{offset}, #{pageSize}注意MySQL模式下LIMIT偏移量和行数的顺序别写反。批量插入在达梦上的写法MySQL式的INSERT INTO ... VALUES (...), (...), (...)在达梦某些版本也能用但最稳妥的还是用FORALL或者MyBatis的foreach拼接多条INSERT ALL INTO ... SELECT ... FROM DUAL写法。实际项目里数据量超过几百条时我倾向于使用MyBatis的batch执行器把ExecutorType.BATCH配上稳定性更好。6.4 一个我最近实测通过的案例最后分享一个实战中确认过的组合。项目用的是SpringBoot 2.7 MyBatis Plus Druid 达梦8。MyBatis Plus的Page分页默认能适配达梦但前提是PaginationInnerInterceptor里配置了达梦的方言。在配置类里加上PaginationInnerInterceptor paginationInterceptor new PaginationInnerInterceptor(DbType.DM);这样生成的LIMIT分页语句才能被达梦正确解析。如果没配默认按MySQL处理在某些达梦版本上会报SQL语法错误。另一个细节是逻辑删除。MyBatis Plus默认的逻辑删除是UPDATE ... SET deleted 1 WHERE ...这在达梦上没问题。但如果实体类字段是LocalDateTime类型MyBatis Plus自动填充功能要求数据库支持对应的日期类型达梦的TIMESTAMP和DATETIME都行记得建表时别用长度不合适的类型。我个人在实际操作中的体会是达梦数据库整体上手成本比想象中低很多。只要理解了大小写规则、模式概念、分页方言这三个核心点日常SQL开发几乎不会遇到什么大障碍。真正消耗时间的反而是应用层连接配置和迁移后SQL的细节校验。这个总结是我在实际项目中“踩坑—查证—修复—沉淀”后的结果希望能帮你在达梦上少走几步冤枉路。你后续如果遇到哪些达梦相关的SQL问题欢迎带着具体场景再讨论。
返回列表