varchar(N)表示字段最多保存N个字符(注意不是字节,MySQL早期版本才是字节),字母(1字节)、汉字(3字节)、emoji表情符号(4字节)都算一个字符。
需要注意的是网上涉及到varchar长度的文章大多都是基于字节单位讨论的,而不是字符单位,varchar最大长度是65535个字节(但需要使用1~2个字节保存字符串长度,所以实际可用长度稍小于65535个字节),那么是多少个字符呢?字节数和字符数的转换受字段的字符集设定影响,在utf8中一个字符最多可占3个字节(如汉字),而在utf8mb4中一个字符最多可占4个字节(如emoji表情符号),字节转字符是以单个字符最大占用字节数为基础:
utf8为(65535-2)÷3≈21844个字符,即varchar(N)中N的最大值21844。
utf8mb4为(65535-2)÷4≈16383个字符,即varchar(N)中N的最大值16383。
需要特别说明的是在同一张表中varchar最大长度限制是所有char字段和varchar字段共享的(以下均假设字符集为utf8mb4),例如某表有三个varchar字段,分别是varchar(N1)、varchar(N2)、varchar(N3),那么(N1+N2+N3)不能大于16383,甚至等于16383都不行,因为每个字段还需要用1~2个字节保存字符串长度。最极端的情况是,创建了一个varchar(16383)字段就无法再创建varchar字段。
varchar(255)和varchar(256)的区别:长度不超过255只需要1个字节保存字符串长度,长度超过255则需要2个字节保存字符串长度。在创建字段时如果不指定长度,那么char和varchar都默认为255,所以如果没有特殊需求一般使用varchar(255)。
阿里巴巴开发手册原文:【强制】varchar是可变长字符串,不预先分配存储空间,长度不要超过5000,如果存储长度大于此值,定义字段类型为text,独立出来一张表,用主键来对应,避免影响其它字段索引效率。
在插入记录时如果字段值长度超过了N就会报“Fatal error: Uncaught PDOException: SQLSTATE[22001]: String data, right truncated: ...”,所以必须使用try-catch捕获异常,可以先用mb_strlen()获取字段值长度,确保其没有超过N再插入。
🖥️ 当字符串长度超过N时,如何自动截断并插入
在默认配置下(即使用缺省值),如果字符串长度超过N,那么插入记录就会报错,但是可以在配置文件里修改sql_mode配置项的值实现自动截断并插入。
sql_mode配置项缺省值:ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
只要将“STRICT_TRANS_TABLES”删除即可,该参数表示开启严格模式,将其删除即可关闭严格模式。
说明①:可执行SQL语句“SELECT @@sql_mode;”查询当前sql_mode配置项的值。
说明②:STRICT_TRANS_TABLES不仅影响varchar类型字段,还会影响int类型字段(插入超出范围的数字会报错)。
说明③:生产环境下应该始终开启严格模式,并在程序中进行长度校验以确保数据安全。