varchar(255)在utf8mb4下最多占1020字节;text限制65535字节而非字符数;需用describe和show create table查字段实际字节容量及编码设置。

查字段真实字节容量,别只看字符数
报错说 Data too long for column,但你确认过字段实际能存多少字节吗?VARCHAR(255) 在 utf8mb4 下最多占 255 × 4 = 1020 字节,不是 255 字节——中文、emoji、生僻字都按 4 字节算。而 TEXT 类型限制的是字节数(TEXT 最多 65535 字节),不是字符数。
必须立刻执行这两条命令:
-
DESCRIBE table_name;看字段类型和长度 -
SHOW CREATE TABLE table_name;确认该列是否显式指定了CHARSET和COLLATE;哪怕表默认是utf8mb4,单列也可能被建表语句覆盖成latin1或旧版utf8
确认客户端连接编码是否一致
同一个 INSERT 语句,手动在 MySQL CLI 里执行成功,但通过 mysql -u xxx 就报错?八成是连接编码不匹配。SQL 文件是 UTF-8 编码保存的,但命令行客户端没指定 <code>--default-character-set=utf8mb4,MySQL 就按服务器默认(比如 latin1)去解析文件,导致中文被错误解码、字节数膨胀。
验证当前 session 编码:
SELECT @@character_set_client, @@character_set_connection, @@character_set_results;- Java 应用必须在 JDBC URL 加上
?characterEncoding=utf8mb4&useUnicode=true - 命令行导入时强制指定:
mysql -u root -p --default-character-set=utf8mb4 database_name
区分非法字符和超长字符:LENGTH() vs CHAR_LENGTH()
“非法字符”常是误判——真正问题是某些字符(如补充平面 emoji ?、U+1F480)在 utf8mb4 下占 4 字节,但应用层用 String.length() 或 SUBSTRING(col, 1, 255) 截的是字符数,不是字节数。结果插入前看似合规,入库时却因字节超限被拒。
排查时用这两个函数对比:
-
SELECT LENGTH(description), CHAR_LENGTH(description) FROM sys_config LIMIT 10;—— 如果前者远大于后者,说明存在多字节字符 - 在 Java 中校验必须用:
value.getBytes(StandardCharsets.UTF_8).length ,而不是 <code>value.length() - 数据库内临时观察:
SELECT HEX(description) FROM sys_config WHERE id = 2;看是否出现F0 9F...类似四字节序列
TEXT 类型也会报 Data too long?检查是否真超 65535 字节
别以为用了 TEXT 就万事大吉。TEXT 的硬限制是 65535 字节(不含行开销),不是字符数。含大量中文或 base64 的日志、JSON、富文本极易踩中。
安全做法:
- 先测真实字节数:
SELECT MAX(LENGTH(content)) FROM logs_table;—— 结果若接近或超过 65535,必须升到MEDIUMTEXT -
ALTER TABLE logs_table MODIFY COLUMN content MEDIUMTEXT;(注意:MEDIUMTEXT支持约 16MB) - JDBC 驱动(如 Connector/J 8.0+)会在发送前主动校验长度,抛出异常比数据库静默截断更早——所以问题常暴露在应用层,而非 MySQL 错误日志
最容易被忽略的一点:同一个字段,在不同连接编码下,LENGTH() 返回值完全不同;而报错时的“超长”,永远是以当前 session 的字符集为准计算的字节数。不锁死 client/connection/table/column 四层编码一致,光调大字段只是把问题延迟爆发。











