达梦数据库踩坑:BLOB 数据类型 存中文文本读取变成十六进制乱码,CLOB 才是字符串大文本正确选择
📅 2026/7/15 21:28:48
👁️ 阅读次数
📝 编程学习
一、问题现象
项目使用 SpringBoot + MyBatis-Plus + 达梦 DM8 开发,AI 分析结果表中存在两类大文本字段:
CONCLUSION、SUMMARY:字段类型CLOB,前端 / 数据库客户端查询中文正常展示;SUGGESTION、BASIS:字段类型BLOB,查询出来不是可读中文,而是一串E59BA0E694BF...十六进制字符串。
数据库客户端、接口返回、后台日志全部都是十六进制 HEX 编码,肉眼完全无法识别中文内容,接口业务展示直接乱码失效。
二、根本原因拆解
1. BLOB 与 CLOB 本质区别(达梦数据库)
| 类型 | 存储内容 | 适用场景 | 编码处理 |
|---|---|---|---|
CLOB | 字符大对象 | 纯文本、中文、JSON、长文案 | 数据库自动绑定字符集(UTF-8),读写自动编解码,JDBC 直接映射 JavaString |
BLOB | 二进制字节大对象 | 文件、图片、二进制流、字节数组 | 只存原始字节,不绑定字符集,JDBC 读取返回原始 byte 数组 |
2. MyBatis-Plus + 达梦 JDBC 联动产生的 HEX 乱码
我们业务中字段存储的是 JavaString类型中文文本,但表定义错用BLOB:
- 写入流程:Java String → JDBC 驱动将字符串转为 UTF-8 字节数组 → 存入 BLOB 二进制字段;
- 读取流程:查询 BLOB 字段 → JDBC 返回原始 byte [] → MyBatis-Plus 自动将字节数组转为十六进制 HEX 字符串展示;
- 最终表现:数据库里存的是中文 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); }缺陷:所有查询接口都要额外转换,增加大量冗余代码,后续新增字段极易重复踩坑。
四、开发规范避坑指南
- 文本类大内容统一使用 CLOB长文本、AI 返回文案、JSON、评论、政策说明、操作日志文本等,一律定义
CLOB; - BLOB 仅用于二进制文件图片、PDF、压缩包、媒体文件等二进制流才使用
BLOB,禁止存放字符串; - 建表 SQL 统一校验字段类型 建表脚本提交前核对大文本字段,杜绝把业务字符串定义为 BLOB;
- 达梦类型转换限制提前知晓
- VARCHAR/CHAR ↔ CLOB、BLOB ↔ CLOB 无法直接
MODIFY修改,必须新增迁移; - BLOB 有数据时,不支持直接转为任何字符类型。
- VARCHAR/CHAR ↔ CLOB、BLOB ↔ CLOB 无法直接
五、总结
本次乱码问题核心不是编码、驱动、MyBatis 配置问题,而是数据库字段类型选型错误:把字符串文本存进了二进制 BLOB 字段。 达梦数据库区分字符大对象 CLOB 与二进制大对象 BLOB,二者底层存储逻辑、JDBC 映射规则完全不同,混用会直接导致 HEX 十六进制乱码。 开发时严格区分业务数据类型,文本统一 CLOB、文件二进制统一 BLOB,从根源规避此类问题。
编程学习
技术分享
实战经验