达梦数据库踩坑:BLOB 数据类型 存中文文本读取变成十六进制乱码,CLOB 才是字符串大文本正确选择

📅 2026/7/15 21:28:48 👁️ 阅读次数 📝 编程学习
达梦数据库踩坑:BLOB 数据类型 存中文文本读取变成十六进制乱码,CLOB 才是字符串大文本正确选择

一、问题现象

项目使用 SpringBoot + MyBatis-Plus + 达梦 DM8 开发,AI 分析结果表中存在两类大文本字段:

  1. CONCLUSIONSUMMARY:字段类型CLOB,前端 / 数据库客户端查询中文正常展示;
  2. SUGGESTIONBASIS:字段类型BLOB,查询出来不是可读中文,而是一串E59BA0E694BF...十六进制字符串。

数据库客户端、接口返回、后台日志全部都是十六进制 HEX 编码,肉眼完全无法识别中文内容,接口业务展示直接乱码失效。

中文数据变为HEX编码

二、根本原因拆解

1. BLOB 与 CLOB 本质区别(达梦数据库)

类型存储内容适用场景编码处理
CLOB字符大对象纯文本、中文、JSON、长文案数据库自动绑定字符集(UTF-8),读写自动编解码,JDBC 直接映射 JavaString
BLOB二进制字节大对象文件、图片、二进制流、字节数组只存原始字节,不绑定字符集,JDBC 读取返回原始 byte 数组

2. MyBatis-Plus + 达梦 JDBC 联动产生的 HEX 乱码

我们业务中字段存储的是 JavaString类型中文文本,但表定义错用BLOB

  1. 写入流程:Java String → JDBC 驱动将字符串转为 UTF-8 字节数组 → 存入 BLOB 二进制字段;
  2. 读取流程:查询 BLOB 字段 → JDBC 返回原始 byte [] → MyBatis-Plus 自动将字节数组转为十六进制 HEX 字符串展示;
  3. 最终表现:数据库里存的是中文 UTF-8 字节,查出来变成一串十六进制编码,肉眼看不到正常中文。

3. 为什么 CLOB 字段无问题

CLOB是字符型大对象,达梦 JDBC 驱动识别为文本类型,会自动根据库字符集完成字节 <-> 字符串转换,MyBatis 直接映射为 Java String,读写全程中文正常,不会出现十六进制乱码。

三、两种修复方案

方案一:数据库层修复(推荐,永久解决)

核心逻辑:达梦不支持BLOB直接ALTER MODIFY改为CLOB,必须走「新增临时 CLOB 字段 → 迁移数据 → 删除旧 BLOB 字段 → 重命名」流程。 以AUDIT_SUGGESTION字段举例:

-- 1. 新增临时CLOB字段 ALTER TABLE TEST.ANALYSIS_RESULT ADD TMP_AUDIT_SUGGEST CLOB; -- 2. 将BLOB二进制数据转为字符串写入CLOB(达梦内置函数UTL_RAW.CAST_TO_VARCHAR2) UPDATE XF_TEST.ANALYSIS_RESULT SET TMP_AUDIT_SUGGEST = UTL_RAW.CAST_TO_VARCHAR2(AUDIT_SUGGESTION); COMMIT; -- 3. 删除原有BLOB字段 ALTER TABLE TEST.ANALYSIS_RESULT DROP COLUMN SUGGESTION; -- 4. 临时字段重命名为原业务字段名 ALTER TABLE TEST.ANALYSIS_RESULT RENAME COLUMN TMP_AUDIT_SUGGEST TO AUDIT_SUGGESTION;

CLASSIFY_BASIS字段执行完全相同流程即可。

方案二:代码层临时兼容(不推荐,治标不治本)

如果暂时无法改表结构,在实体类 / 转换工具手动将 HEX 字节数组转回 UTF-8 字符串:

/** * BLOB十六进制字符串转中文文本 */ public static String hexBlobToText(String hexStr) { if (hexStr == null || hexStr.isEmpty()) { return ""; } byte[] bytes = new byte[hexStr.length() / 2]; for (int i = 0; i < bytes.length; i++) { int high = Character.digit(hexStr.charAt(2 * i), 16); int low = Character.digit(hexStr.charAt(2 * i + 1), 16); bytes[i] = (byte) (high << 4 | low); } return new String(bytes, StandardCharsets.UTF_8); }

缺陷:所有查询接口都要额外转换,增加大量冗余代码,后续新增字段极易重复踩坑。

四、开发规范避坑指南

  1. 文本类大内容统一使用 CLOB长文本、AI 返回文案、JSON、评论、政策说明、操作日志文本等,一律定义CLOB
  2. BLOB 仅用于二进制文件图片、PDF、压缩包、媒体文件等二进制流才使用BLOB,禁止存放字符串;
  3. 建表 SQL 统一校验字段类型 建表脚本提交前核对大文本字段,杜绝把业务字符串定义为 BLOB;
  4. 达梦类型转换限制提前知晓
    • VARCHAR/CHAR ↔ CLOB、BLOB ↔ CLOB 无法直接MODIFY修改,必须新增迁移;
    • BLOB 有数据时,不支持直接转为任何字符类型。

五、总结

本次乱码问题核心不是编码、驱动、MyBatis 配置问题,而是数据库字段类型选型错误:把字符串文本存进了二进制 BLOB 字段。 达梦数据库区分字符大对象 CLOB 与二进制大对象 BLOB,二者底层存储逻辑、JDBC 映射规则完全不同,混用会直接导致 HEX 十六进制乱码。 开发时严格区分业务数据类型,文本统一 CLOB、文件二进制统一 BLOB,从根源规避此类问题。