)
一、前言业务常见痛点开发中对接 SQL Server 数据库时绝大多数人都会遇到一个经典坑明明前端输入字符数没超入库却报字段超长、数据被截断本地测试正常服务器Linux环境必现异常。核心原因SQL Server 的 varchar 是字节限制不是字符限制且默认中文排序规则编码和Java默认编码不统一导致前端、Java校验、数据库存储三方长度判定不一致。本文基于最常用的数据库字段定义[YDJH] varchar(50) COLLATE Chinese_PRC_CI_AS NULL手把手讲透编码原理、字节占用规则、Java正确校验方案彻底根治超长报错问题。二、SQL Server 核心编码规则必看2.1 Chinese_PRC_CI_AS 底层编码SQL Server 中国大陆默认排序规则Chinese_PRC_CI_AS对应的底层代码页为CP936GBK编码这是行业通用标准。编码字节占用规则英文、数字、半角符号1字节/个中文汉字、全角符号2字节/个2.2 varchar(50) 真实存储容量重点varchar(n) 代表最大 n 字节不是 n 个字符。针对 varchar(50)纯中文场景最多存储25个汉字50/2混合场景汉字英文/数字混合按实际字节累加超出50字节数据库直接截断数据或抛出超长异常2.3 新旧排序规则区别拓展避坑Chinese_PRC_CI_AS老版纯 GBK 编码无生僻字支持Chinese_PRC_90/100/130_CI_AS新版底层 GB18030兼容GBK支持生僻字部分生僻字占4字节普通业务场景两种规则用GBK校验完全够用。2.4 区分 nvarchar 关键知识点很多开发者混淆两类字段这里明确区分varchar非UnicodeGBK编码按字节校验nvarcharUnicode编码UTF-16LE中英文均2字节直接按字符长度 str.length() 校验三、Java 校验常见致命错误3.1 错误1使用无参 getBytes()// 绝对禁止跨环境失效 byte[] bytes str.getBytes();无参方法依赖操作系统默认编码Windows默认GBK侥幸正常Linux/Mac/服务器默认UTF-8中文3字节/个后果服务器端计算字节数远大于数据库实际字节数出现明明没超长却被Java误判拦截或校验失效导致入库报错。3.2 错误2使用 StandardCharsets 常量校验很多同学想使用JDK自带的StandardCharsets但发现里面没有GBK常量StandardCharsets 仅支持US_ASCII、ISO_8859_1、UTF-8、UTF-16系列不包含GBK/GB18030。严禁用 UTF-8 校验本字段UTF-8中文3字节和SQL Server GBK字节规则完全不匹配100%误判。四、Java 正确精准校验方案可直接复用4.1 核心原理必须手动指定GBK编码让Java计算的字节数完全对齐 SQL Server DATALENGTH()结果。4.2 完整工具类长度校验自动截断import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; /** * SQL Server varchar(GBK) 字段长度校验工具 * 适配排序规则Chinese_PRC_CI_AS */ public class SqlVarcharCheckUtil { /** * 获取字符串GBK字节长度与数据库DATALENGTH完全一致 * param str 待校验字符串 * return GBK字节数 */ public static int getGbkByteLength(String str) { if (str null || str.isEmpty()) { return 0; } try { Charset gbkCharset Charset.forName(GBK); return str.getBytes(gbkCharset).length; } catch (IllegalCharsetNameException | UnsupportedCharsetException e) { throw new RuntimeException(当前JDK环境不支持GBK编码数据库字段校验失败, e); } } /** * 校验是否符合 varchar(50) 字节规范 * param text 待校验文本 * return true合规false超长 */ public static boolean isVarchar50Valid(String text) { if (text null) { return true; } return getGbkByteLength(text) 50; } /** * 自动截断至varchar(50)最大字节避免入库报错 * param val 原始文本 * return 截断后合规文本 */ public static String trimToVarchar50(String val) { if (val null || isVarchar50Valid(val)) { return val; } // 逐字符截断保证GBK字节不超50 int index 0; while (index val.length() getGbkByteLength(val.substring(0, index 1)) 50) { index; } return val.substring(0, index); } }4.3 数据库校验对照SQL可通过以下SQL验证Java结果准确性两者数值完全一致-- 查看字段实际占用字节数 SELECT DATALENGTH(YDJH) AS 实际字节数, LEN(YDJH) AS 字符数 FROM 表名DATALENGTH真实存储字节数和Java GBK计算结果一致LEN纯字符个数无参考意义五、全文核心总结干货速记SQL Server varchar(50) Chinese_PRC_CI_ASGBK编码最大50字节最多25个纯汉字。禁止使用无参 getBytes()跨环境编码不一致必出BUG。StandardCharsets无GBK必须通过Charset.forName(GBK)获取编码。varchar按字节校验nvarchar按字符校验切勿混淆。服务器Linux环境必须指定GBK否则UTF-8三字节中文会导致校验完全失效。六、拓展建议如果业务需要支持生僻字、全量中文兼容可将编码替换为GB18030仅需修改代码中编码名称适配新版SQL Server排序规则兼容性更强。