You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server JDBC读取Latin1字段0x8F字符转UTF-8结果异常

问题原因

该问题并非JDBC驱动逻辑缺陷,核心原因是SQL Server排序规则绑定的代码页映射规则与你的预期不符:

  • 你使用的SQL_Latin1_General_CP1_CS_AS排序规则关联的代码页是Windows-1252(CP1252),它和常被混淆的ISO-8859-1编码在0x80~0x9F字节范围的映射规则存在本质差异:ISO-8859-1中0x8F对应U+008F控制字符,但CP1252规范中0x8F属于未定义的无效字节,没有匹配的Unicode字符。
  • 无论使用官方mssql驱动还是jTDS驱动,读取varchar(非Unicode)类型字段时,都会严格遵循字段排序规则对应的代码页做字节到Unicode的解码:遇到无有效映射的0x8F字节时,会直接替换为Unicode替换字符U+FFFD。当你调用resultSet.getString()拿到字符串对象时,原始字节信息已经丢失,后续再转UTF-8自然得到efbfbd,这和你直接在Java中定义"\u008f"再转码的场景逻辑完全不同——后者从一开始就没有经过代码页解码的丢码环节。
  • 你在SQL Server 2017、2019以及两类驱动环境下都能复现问题,恰好说明这是SQL Server本身的代码页规则导致的,和驱动版本、数据库大版本无关。
验证方式

你可以直接在SQL Server客户端执行如下T-SQL,不需要经过JDBC就能看到数据库引擎本身的映射结果:

SELECT CONVERT(nvarchar(10), CONVERT(varchar(10), 0x8F));

执行返回的结果就是U+FFFD,证明数据库层面就没有把该排序规则下的0x8F字节映射为U+008F。

修复方案
  • 最彻底的方案是将字段类型从varchar(35)改为nvarchar(35),直接使用Unicode类型存储数据,从根源上避免代码页映射导致的字符丢失问题。
  • 如果暂时无法修改字段类型,查询时不要直接调用getString()读取,改为读取原始字节后自行按ISO-8859-1编码解码,即可得到正确的U+008F字符:
byte[] fieldRawBytes = resultSet.getBytes(1);
String correctStr = new String(fieldRawBytes, StandardCharsets.ISO_8859_1);
// 此时调用convertStrToHex(correctStr)即可得到预期的C28F
  • 注意不要直接在JDBC连接串全局修改默认字符集为ISO-8859-1,否则会导致同库下其他按CP1252规则存储的0x80~0x9F范围有效字符(比如存储为0x80的欧元符号€)出现解码错误。

内容的提问来源于stack exchange,提问作者Sergo Akopdjanov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 23:54:22