业务校验必须用CHAR_LENGTH(),因它按Unicode码点计数,与前端JS、Python一致,确保昵称限10字、短信70字等用户感知长度准确;LENGTH()仅用于字节敏感场景如判断存储上限或底层截断,混用会导致emoji误放行、中文截断、前后端长度对不上。

业务校验必须用 CHAR_LENGTH(),LENGTH() 只在极少数字节敏感场景下才用——混用会导致前端显示截断、长度限制失效、emoji 被误放行。
查字段是否含中文:用 LENGTH() != CHAR_LENGTH()
UTF8MB4 下英文、数字、空格都占 1 字节,一个字符 = 1 字节,所以 LENGTH() 和 CHAR_LENGTH() 相等;而中文、日文、韩文、emoji 等多字节字符会让 LENGTH() 大于 CHAR_LENGTH()。
-
SELECT name FROM user WHERE LENGTH(name) != CHAR_LENGTH(name)→ 找出含非 ASCII 字符的记录 - 注意:
LENGTH('a') == CHAR_LENGTH('a')(都是 1),LENGTH('你') == 3(utf8mb4 下),CHAR_LENGTH('你') == 1 - 不能反推:结果相等 ≠ 全是英文(比如两个 emoji 各占 4 字节,
LENGTH('??') == 8,CHAR_LENGTH('??') == 2,仍不等)
用户输入长度限制:无条件用 CHAR_LENGTH()
前端 JS 的 str.length、Python 的 len() 都按 Unicode 码点计数,和 CHAR_LENGTH() 行为一致。用 LENGTH() 做校验会直接对不上。
- 昵称限 10 字:写
WHERE CHAR_LENGTH(nickname) > 10,不是LENGTH(nickname) > 10 - 短信内容统计 70 字:用
CHAR_LENGTH(content),否则一个 emoji 就算 4 字节,但用户只认为是「1 个字」 - 触发器里截断:用
LEFT(nickname, 10)(按字符),别用SUBSTR(nickname, 1, 10)(默认按字节,可能劈开 emoji)
判断是否超列物理上限:必须用 LENGTH()
MySQL 的 VARCHAR(100) 是按「字符数」定义的,但底层存储受字符集限制:utf8mb4 下最多存 100 个字符,但总字节数不能超 4×100 = 400 字节(实际因行格式有额外开销,通常 ≤ 65535 字节)。插入时若字节超限,会报错 ERROR 1406 (22001): Data too long for column。
- 想提前拦截该错误:用
LENGTH(content) > 100判断(前提是字段是VARCHAR(100) CHARACTER SET utf8mb4) - 确认字段真实字符集:
SHOW CREATE TABLE user,别信建表语句里没显式写的默认值 - 连接字符集影响
LENGTH()解析:SELECT @@character_set_client,设成utf8mb4再测才准
真正容易被忽略的是:同一个字段,CHAR_LENGTH() 稳定反映「人眼看到几个字」,LENGTH() 却随连接字符集、字段字符集、甚至字符串字面量编码动态变化。线上环境一旦 SET NAMES latin1,LENGTH('你好') 可能变成 2 —— 不是 bug,是设计如此。别指望它“看起来合理”。


















