Liquibase向MS SQL插入数据时Blob列引发特殊字符乱码问题
问题原因
- 核心是 Liquibase 4.2.2 + MSSQL JDBC 8.4.1 版本在处理同时包含 Unicode 文本(NVARCHAR 类型)和 BLOB 字段的插入语句时,在默认校对规则为 Latin1_General_CI_AS 的数据库环境下存在参数类型推导缺陷:当插入语句中包含 BLOB 类型参数时,JDBC 驱动会错误将前面的 NVARCHAR 字符串参数按照 Latin1 单字节字符集转码后传输,西里尔文这类非 Latin1 字符无法被编码,直接被替换为
?存入数据库。没有 BLOB 字段的插入语句不会触发这个推导错误,所以 Unicode 内容可以正常存储。 - 本地环境无法复现大概率是因为本地数据库实例/库的默认校对规则不是 Latin1_General_CI_AS,参数推导逻辑走了另一个分支,不会触发编码转换错误。
可行解决方案
显式指定 NVARCHAR 字段的 valueType(最优先推荐)
给所有变更集中 NVARCHAR 类型字段的插入配置加上valueType="NVARCHAR"属性,强制 Liquibase 和 JDBC 驱动按照 Unicode 类型处理参数,不会被错误转码,示例如下:<column name="NAME_NATIVE" value="Белару́сь" valueType="NVARCHAR"/>所有 NVARCHAR 类型的列(NAME_LATIN、ADDR_FORMAT、REQUIRED_FIELDS、ZIP_REGEX 等)都要加上这个属性配置即可解决问题。
拆分 BLOB 字段的插入逻辑
把 BLOB 字段的写入拆成独立的变更集:先执行不带 BLOB 字段的插入操作写入所有文本内容,再单独执行 update 语句更新对应行的 FLAG 字段,避开同一条插入语句同时存在 BLOB 和 Unicode 文本参数的场景。升级组件版本
把 Liquibase 升级到 4.10 以上版本,MSSQL JDBC 驱动升级到 12.2 以上版本,这两个版本官方已经修复了大量混合类型参数的推导缺陷,这类编码错误基本不会再触发。临时验证方案
可以在数据库 JDBC 连接串中加上sendStringParametersAsUnicode=true参数,强制所有字符串参数按照 Unicode 格式传输,但该配置可能会影响普通 VARCHAR 字段的查询性能,只建议做问题验证使用,不推荐长期在生产环境配置。
内容的提问来源于stack exchange,提问作者ses
相关产品推荐
相关产品推荐

