最近把一个跑了两年的达梦数据库从旧补丁版本升到了新版本,前前后后折腾了两天,踩了不少坑,也攒了不少经验。达梦数据库版本升级这个事,听着像个常规运维操作,但实际上从备份验证、参数兼容到应用侧驱动适配,每一步都可能让整个切换前功尽弃。这篇分享是我个人对达梦数据库版本升级的一次完整复盘,包括升级前准备、方案选型、核心实操步骤和故障排查,给准备做达梦升级的DBA、运维同学,以及在应用侧接达梦的开发者一个参考。如果你手头正好有一台达梦要升,或者只是想搞清楚升级到底涉及哪些环节,这篇应该能帮上忙。
1. 升级前先想清楚:达梦版本升级到底在升什么
1.1 达梦版本升级的两类典型场景
达梦数据库目前最常用的是DM8系列,产品线上还有DPC、DMETL这些配套组件,不过大多数业务场景里,DBA面对的就是一个标准的DM8实例。版本升级在多数项目里分成两个方向:一个是在DM8内部从小版本往新补丁版本走,比如从较早的8.1.x补丁版本升级到更新的稳定版本,主要目的是拿到官方针对某些bug、性能问题或安全漏洞的修复;另一个是从更早的版本往DM8迁,比如有些项目之前用的是DM7甚至更早的版本,这类升级就不只是打补丁,而是跨度比较大的整体迁移,涉及数据字典、参数体系、工具链的全面变化。
我这次升级属于前者。原来的库是8.1.x的早期补丁版本,业务上遇到一个批量提交场景下偶发的性能回退问题,官方在新补丁中做了优化,同时修了几个安全相关的漏洞,所以决定升级。这里也提醒一下:决定升级前,先想清楚升级到底能解决什么。为了升级而升级,或者听说新版稳定就盲目升,最容易翻车。最好有一条明确理由,比如遇到某个bug、需要某个新特性、或者有兼容性风险要规避,这样升级目标清晰,验证也有依据。
1.2 为什么不能直接拿旧数据目录启动新版程序
很多第一次做达梦升级的人会有一个朴素想法:把新版安装好,数据目录还是用旧库的,直接启动不就行了。这个思路在达梦里走不通,原因在于达梦的数据文件内部带着版本相关的结构信息。旧版本的数据字典、系统表结构、内部日志格式,在不同版本之间是有差异的。直接拿新版dmserver进程去启动旧数据目录,轻则启动阶段直接报错,重则启动起来之后跑特定SQL时报内部错误。
用个生活化类比:升级操作系统不是把新内核文件拷贝进旧系统盘就完事,底层格式和元数据需要重新对齐,否则表面能开机,一跑业务就各种莫名问题。达梦版本升级的核心工作,就是处理数据字典和内部结构的一致性。官方提供的升级包、升级脚本、配套的迁移工具,本质上都是在帮你解决这个一致性问题。所以思路要摆正:升级不是替换安装目录,而是让数据在版本变化之后还能被新版本正确解释、稳定运行。
项目里经常遇到的"模式错误"问题,在升级场景里就很典型。很多时候不是库坏了,而是版本切换后某个系统对象或者默认模式没有正确对齐,导致SQL解析阶段失败。理解了版本兼容背后的原理,再看这类报错就不会慌。
2. 升级前准备:这几件事没做完先别动库
2.1 环境盘点:版本、路径、字符集一个都不能漏
动手之前,我先把整个环境摸了一遍,列了张清单:当前数据库版本号、补丁版本、安装目录、数据目录、实例名、服务名、监听端口、数据库字符集、页大小、大小写敏感设置、兼容模式、归档模式、定时备份任务、应用连接账号和权限。这几个信息看起来琐碎,但每一项都可能在升级中变成拦路虎。
查版本和实例信息,在disql里执行:
SQL> select * from v$version; SQL> select name, status$ from v$instance; SQL> select id_code from v$instance;字符集、页大小、大小写敏感这三个初始化参数,在升级后最容易引发问题。数据迁移、连接乱码、长度判断异常,根源基本都在这里。所以盘点阶段一定要把这些记准确,最好写进升级方案文档里。另外,实例是单机还是主备,归档日志开没开,定时备份策略是什么,也要一并确认。这些信息决定了后面选什么升级方案。
我自己会把环境信息和升级后的目标版本做个对比表,一个参数一个参数核对。核到发现原库的兼容模式参数和官方升级手册要求的默认值不一致,提前知道了,后面处理起来就不慌。
2.2 全量备份和备份可恢复性验证
备份是整个升级过程里最不能省的一步。在disql里做全量备份:
SQL> backup database full backupset '/dm/backup/full_20250101';这里有几个容易忽略的细节。备份目录的属主必须是dmdba用户,不然写不进去;磁盘空间要提前确认够用,备份集大小通常会接近整个数据文件的实际占用;备份完成后习惯性看一眼备份集信息,确认不是空的。
比备份更重要的一步是备份可恢复性验证。"备份成功"和"备份能用"是两回事。我见过不少案例,备份任务天天跑,日志显示成功,真到恢复的时候发现缺了某个归档文件或者备份集损坏。所以我会把备份集拷贝到一块独立盘或者另一台机器,用dmrman在临时目录做一次restore验证,确认能完整恢复成一个可用的库目录。这一步熟练之后花不了多少时间,但能让你在后续操作中底气完全不同。
备份策略上,升级前那一份全量备份要单独留存,和日常备份区分开。最好复制成两份,一份放在本机之外的地方,防止升级过程中误操作把备份覆盖掉。
2.3 升级包、文档和回退预案准备
升级包要从官方渠道获取,并且确认和当前操作系统、CPU架构匹配。达梦的安装包区分x86_64、ARM、龙芯等平台,不同平台不能混用。还要留意升级包说明里写的起始版本要求,如果当前版本比要求的起始版本还低,往往需要先升一个中间版本,再升到目标版本,不能一步跨太多。每个版本之间能跳多少级,官方文档里通常有明确说明,按照那个来,别自己发挥。
回退预案也要在升级前写好。旧安装目录先别删,注册的服务脚本复制一份保存,重要配置文件备份起来。升级出现问题时,最快回退方式是把旧服务恢复起来,重新拉起旧版本。这些步骤不用多复杂,但一定要提前写清楚,别等到出问题再现场想。
3. 升级方案选型:停机替换还是原地升级
3.1 停机替换加数据恢复:最稳的通用路线
达梦版本升级没有放之四海而皆准的唯一方案,但绝大多数场景下,我最推荐的是"停机替换加数据恢复":先停应用、停数据库,做最后一次全量备份;新环境装好新版本、初始化好新实例;然后把数据恢复或者迁移过去;最后核对数据和参数,切换业务。
这个方案听着笨,但优点是每个环节都是显式可控的。备份、安装、恢复、验证一步一个脚印,出问题可以随时回退到旧环境。相比原地执行升级脚本,它的不确定性更小,尤其适合生产库。我这次接近1T的库就是这么处理的,整个过程唯一要花时间的就是备份文件拷贝和恢复时的校验,但每一步都知道在干什么,心里踏实。
适用场景很明确:有停机窗口,数据量不大到无法接受恢复时间,对操作可控性要求高。满足这三点,走这个路线基本不会出大乱子。
3.2 官方升级脚本的小版本原地升级
达梦官方的升级包,通常会带一套升级脚本,升级脚本在安装目录的scripts/upgrade下面,文件名往往以UNL开头,里面按顺序组织了一批SQL和内部升级逻辑。连接数据库后,按照官方手册说明,逐一执行对应的升级脚本,启动库,跑完脚本再重启,就能完成小版本升级,不用迁移数据。
这个方式省事,但前提很严格:当前环境必须符合官方手册的约束条件,比如版本区间、参数默认值、数据库状态;执行升级脚本的过程也必须按顺序完整跑完,中间任何一步报错中断都要谨慎处理。有些系统视图升级、系统包编译、权限同步的逻辑是分步的,跳过一步可能后面执行特定功能时报错。
所以我通常的建议是:如果只是小版本补丁升级、库结构不复杂、官方手册明确支持,可以尝试原地升级;但升级前备份一步都不能省。所谓"不用迁移数据"不代表"不用备份数据"。
3.3 主备与集群环境的滚动思路
如果业务是主备架构或者达梦集群(DSC),理论上可以先升级备节点,验证没问题之后切换,再升级原主节点。这样能缩短业务停机时间,甚至做到不停业务的滚动升级。但这个方案对操作者的要求也更高:主备切换的细节在不同版本之间可能有差异,切换前要确认两个节点的数据一致性、归档同步状态,切换后要做完整的业务验证。
我这次是单节点环境,没有实际走滚动升级的路子,所以这里不展开细节。但值得提一句:如果你的环境是多节点,别照搬单节点的操作流程,先去官方文档确认对应版本的主备升级规范,把切换步骤和回退步骤写在方案里。滚动升级做得好是零停机,做得不好就是双节点同时不可用,风险管控远比省那几分钟停机时间重要。
4. 实操过程实录:从停服到数据恢复的完整步骤
4.1 停服、备份与备份验证
升级当天,第一步是业务侧发布停机通知,确认应用流量已经停了。然后停达梦服务:
systemctl stop DmServiceDMSERVER如果你的环境是手工注册的服务,也可以用安装目录下的脚本:
/dameng/app/dmdbms/bin/DmServiceDMSERVER stop服务名以你环境里实际配置为准,不确定的话先看服务列表。停完之后确认进程真的退了:
ps -ef | grep dmserver进程还在就别急着往下走,先弄清楚为什么没停掉。确认进程消失后,做最后一次全量备份。这里我习惯把备份命令写到操作记录里,和执行时间一起留存,方便后面追溯。
备份完成后,快速用dmrman在临时目录做一次restore,验证备份集可用。这一步虽然多花十来分钟,但能避免最坏的情况:旧库已经停了,新库恢复才发现备份有问题,那就进退两难了。
4.2 新版本安装与实例初始化
安装新版本时,我习惯用静默安装。把安装介质放到目标机器,用dmdba用户执行安装命令,按提示填好安装路径、组件选项。安装完成之后,不要急着用默认的库目录,而是手动初始化一个新实例。
初始化命令示例:
/dameng/app/dmdbms/bin/dminit path=/dm/data DB_NAME=DAMENG PAGE_SIZE=8 CHARSET=1 CASE_SENSITIVE=1这里划重点:PAGE_SIZE、CHARSET、CASE_SENSITIVE这三个参数,必须和原库保持一致。页大小不一致可能导致恢复或导入失败;字符集不一致会导致中文乱码;大小写敏感设置不一致,会让原来大小写敏感的SQL行为完全变化,甚至直接报对象不存在。
如果原库这些参数不清楚,用disql连上旧库查系统表确认,不要猜。初始化好之后,注册服务、启动新库,确认能正常登录到disql,再做下一步。
4.3 数据恢复:逻辑导入和物理还原怎么选
数据恢复有两条路线,选择主要看数据量规模和结构复杂度。
逻辑迁移用dexp导出、dimp导入。适合库不大、对象结构相对简单、对效率不敏感的场景。导出时注意用户、schema、权限、序列、自增列这些对象也要一起导出,导入时先建好用户和表空间,注意顺序。逻辑迁移的优点是灵活,可以在迁移过程中调整表结构、表空间,缺点是大数据量下很慢,大字段、复杂对象可能出现个别错误。
物理恢复用dmrman,适合数据量大的生产库,尽量保留原结构。把备份集拷贝到新环境的备份目录,在dmrman里执行恢复:
RMAN> restore database '/dm/data/DAMENG/dm.ini' from backupset '/backup/full_20250101';恢复完成后,如果备份中包含归档日志信息,通常还需要执行recover操作,把数据前滚到一致状态。这一步新版dmrman要求比较严格,每一步按照提示来,日志里会有明确指引。
我这次因为库接近1T,逻辑导出导入明显不现实,所以走了物理备份恢复。整个耗时大头是备份文件拷贝和恢复时的校验,其余环节很快。物理恢复完成后,库的数据内容和原库保持了一致,后续只需要核对参数。
4.4 升级后参数核对与版本确认
数据恢复完成、新库正常启动后,先确认版本:
SQL> select * from v$version;确认显示的版本号已经变成目标版本。接下来逐项核对dm.ini里的关键参数。我习惯把新旧两个版本的dm.ini拿出来做diff,重点关注这几个项:
| 参数项 | 说明 | 备注 |
|---|---|---|
| COMPATIBLE_MODE | 兼容模式 | 与原库不一致会影响SQL行为 |
| LENGTH_IN_CHAR | 字符长度单位 | 会影响字符串长度判断 |
| PAGE_SIZE | 页大小 | 初始化时就要一致,运行后不可改 |
| ARCH_INI | 归档配置 | 升级后要确认归档路径有效 |
| UNDO_RETENTION | 回滚段保留时长 | 会影响长事务和undo空间 |
参数核对不要只看名字一样就放过,有些参数在不同版本里默认值会变。比如归档相关配置如果还指向旧路径,后面跑增量备份就可能失败。把关键参数调整好,重启一次新库,确认参数生效。
到这里,数据侧的升级基本告一段落,但真正的考验还没结束。应用侧能不能连上、业务SQL能不能跑稳,才是升级是否成功的最终判定。
5. 升级后的应用侧验证:连接工具与业务中间件适配
5.1 用navicat和idea连接新库的注意事项
升级完成后第一步,我用连接工具连一下新库。navicat较新版本里内置了达梦驱动,但内置驱动的版本和当前库版本未必匹配。如果连接时报"no suitable driver"或者"类不存在"之类的错误,别去纠结数据库的问题,先去达梦安装目录的drivers/jdbc里拿官方的JDBC驱动jar,比如DmJdbcDriver18.jar,然后在连接配置里手动指定这个驱动包。
idea连达梦也是类似的流程。驱动版本不对的典型表现是:连接配置看着没问题,点测试连接报一堆类加载错误或者驱动版本不支持。换成官方高版本驱动之后基本都能解决。
另外,如果原来在达梦上配置了SSL加密连接,升级恢复之后,新环境的证书和key文件要放到对应路径,否则客户端和服务之间的握手会失败。这种报错看起来像网络问题,又像用户名密码问题,实际上就是证书文件找不到或者路径不对。升级前把SSL相关配置文件和证书存储位置也记录好,能省不少排查时间。
5.2 mybatis+druid+springboot连接达梦的配置要点
业务侧最常见的是Spring Boot加Druid加MyBatis这套组合连达梦。数据源配置一般长这样:
spring.datasource.url=jdbc:dm://localhost:5236/DAMENG spring.datasource.driver-class-name=dm.jdbc.driver.DmDriver spring.datasource.druid.filter.wall.enabled=false spring.datasource.druid.validation-query=select 1这里有两个容易踩的点。第一个是Druid的wall filter对达梦方言的支持程度有限,分页、特殊函数这些场景容易被误判为非法SQL,升级后回归时如果发现某些SQL突然被拦截,大概率是wall filter的问题,测试阶段可以先关闭观察。第二个是项目里如果用了类似jdbc:dm://localhost:5236/DAMENG?compatibleMode=mysql这样的连接串来让SQL方言更靠近MySQL,升级后要确认新版本兼容模式的行为有没有变化。
还有一个常见问题是MyBatis的Mapper XML里写着方言相关的写法,比如分页limit、字符串拼接用concat。升级之后,如果碰到某个接口报SQL语法错误,先检查XML里的写法在新版本方言下是否还适用。这些细节在升级前往往没人注意,但恰恰是回归测试中高频出问题的地方。
5.3 回归测试和性能基线对比
数据恢复完成、应用连上之后,不要急着把所有业务切过去。先在测试环境把核心业务SQL跑一遍,拿执行计划观察新旧版本是否有明显变化。新版优化器行为有变化不奇怪,同一个SQL执行计划变了也正常,重点看耗时和结果是否满足预期。
我会挑三类典型的请求做回归:批量写入、复杂关联查询、报表类大查询。每类都跑几遍,观察响应时间、慢日志有没有新增、事务有没有异常回滚。升级后的前几百条线上请求也要盯一下,把应用日志里的SQL错误、超时、连接异常都记下来。确认一切正常再逐步放量,这个过程不能省。
6. 升级避坑实录:常见问题与排查方法
6.1 报"模式错误"一般不是库坏了
升级后连接执行表查询,报schema不存在、对象找不到或者模式错误,最常见的场景是SQL里的对象名带了旧schema前缀,而升级后默认模式变了,或者兼容模式参数不一致导致模式解析规则变了。
排查路径很直接:先查当前会话的模式:
SQL> select schema_name from user_schemas;再看SQL里访问的对象是不是都在正确的模式下面。最后核对COMPATIBLE_MODE参数是否和原库一致。多数情况下,不是数据丢了,只是模式解析对不上,调整参数或者修正SQL里的对象前缀就解决了。
6.2 恢复后服务启动失败的排查路径
升级恢复后服务起不来,优先看日志。达梦的运行日志在安装目录的log目录下,文件名类似dm_实例名_日期.log。打开日志看第一个报错信息,常见原因无非这么几类:初始化参数和原库不一致、恢复时指定的备份路径不对、归档配置指向了旧路径、数据目录文件属主不是dmdba。
日志第一行报错往往就是根因。比如归档配置指向旧路径,启动时找不到归档文件,把dm.ini里的归档路径改到新环境的实际路径就行。文件权限问题用chown调整后再起服务基本都能解决。
6.3 连接工具连不上新库的常见原因
排查顺序从外到内。先看端口有没有监听:
ss -lntp | grep 5236再看防火墙有没有放行,然后确认实例状态:
SQL> select name, status$ from v$instance;实例状态是OPEN才能正常连接,如果停在MOUNT状态,需要手工执行alter database open。如果一切正常还是连不上,那就回到驱动版本问题上,换官方最新JDBC驱动基本能解决。
6.4 字符集乱码和数据异常的处理
升级后出现中文乱码,十有八九是新库初始化字符集和原库不一致。原库是GB18030,新库初始化成UTF-8,中文字段就会出现乱码或者字符串长度报错。这种问题想靠参数调整绕过去基本没戏,最好的补救方式是用原库相同的字符集重新初始化一个实例,再重新导入或者恢复一次数据。
在数据侧,把原库字符集提前确认清楚,比什么技巧都重要。检查的方法很简单,登录旧disql执行:
SQL> select para_name, para_value from v$dm_ini where para_name='DB_CHARSET';记下这个值,初始化新实例时保持完全一致,字符集这块就不会出问题。
整个升级过程踩下来,我个人最深的体会是:达梦数据库版本升级本身不复杂,复杂的是升级前的准备和升级后的验证。备份能恢复才是真备份,连接工具能连上是第一步,业务SQL跑得稳才是真的成功。如果你也在准备达梦升级,建议先把环境信息列全,备份做扎实,回退方案写清楚,再动手。这篇分享是在实际操作中一点点攒出来的,希望对后来的人少走弯路有点帮助。