MySQL报1366 Incorrect string value 设utf8mb4仍存字符写入错误
MySQL写入utf8mb4字段报1366错误排查与修复
问题现象
向已设置utf8mb4字符集的MySQL表surname字段写入带特殊字符的内容SEGAL‡(末尾为双剑号,对应Unicode U+2021)时,抛出如下异常:
SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xE0' for column 'surname'
当前环境为Laravel 8,数据库连接已显式配置字符集:
'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci',
目标字段字符集与排序规则配置如下:
排查中发现待导入的CSV源文件存在异常:用PHPStorm打开时所有非ASCII字符显示为乱码�,手动指定UTF-8(带/不带BOM)编码打开仍无法正常显示,但同一份文件用Excel打开时所有字符展示正常。
补充排查:用十六进制编辑器检查文件发现,字符ä在文件中仅以单字节8A存储,不符合常规编码规则——单字节Latin1编码下ä存储为E4,UTF-8编码下应为双字节序列C3 A4。
根因定位
首先排除两类常见误判:
- U+2021双剑号的标准UTF-8编码为2字节序列
E2 80 A1,完全在utf8mb4的支持范围内,报错和字段排序规则无关 - Laravel侧的连接字符集配置、字段侧的
utf8mb4配置本身没有问题
核心问题是待导入的CSV源文件不是UTF-8编码,导入流程未做编码转换,非法字节序列被直接传入MySQL触发报错,对应证据如下:
- 十六进制校验结果直接排除UTF-8编码可能:UTF-8为变长编码,所有非ASCII字符首字节范围为
0xC0-0xFD,后续跟随字节范围为0x80-0xBF。文件中出现的单独0x8A、报错中提到的0xE0开头的序列,都是典型的单字节ANSI编码内容被误当UTF-8解析的特征:0xE0在UTF-8规则中需要后续跟随2个合法字节才能组成完整字符,实际传入的内容中该字节后为其他ANSI单字节字符,不满足编码规则,被MySQL判定为非法字符串。 - Excel能正常打开文件是因为它读取无BOM的CSV时,会自动匹配当前系统默认的ANSI代码页解码,不需要文件显式标注编码;PHPStorm默认优先按UTF-8解码,源文件本身不是UTF-8编码,手动强制指定UTF-8打开自然会显示乱码。
修复方案
- 导入环节增加编码转换逻辑
不要直接读取原CSV内容拼接入库,先确认源文件实际编码(这类Excel导出的无BOM CSV,编码通常为导出机器对应的系统默认ANSI代码页,比如西欧环境为Windows-1252/CP1252,中欧环境为Windows-1250/CP1250),读取文件后先转码为UTF-8再执行入库逻辑,示例代码:
如果无法确认源编码,可通过// 读取原CSV二进制内容,第三个参数替换为源文件实际编码 $rawCsvContent = file_get_contents('/path/to/import.csv'); $utf8CsvContent = mb_convert_encoding($rawCsvContent, 'UTF-8', 'CP1252'); // 解析转码后的UTF-8内容,正常走入库逻辑即可mb_detect_encoding函数遍历常见单字节编码做匹配校验,找到可正确解码所有字符的编码即可。 - 源头规避编码问题
后续导出CSV文件时,直接选择「UTF-8(带BOM)」格式保存,所有编辑器、程序读取时都会自动识别为UTF-8编码,不需要额外转码。 - 全链路字符集校验
执行以下SQL检查MySQL服务端、数据库级别的字符集配置,确保全链路统一为utf8mb4,避免连接配置被服务端默认值覆盖:
需确认SHOW VARIABLES LIKE 'character_set%';character_set_server、character_set_database参数值为utf8mb4。
内容的提问来源于stack exchange,提问作者Chuck Le Butt
相关产品推荐
相关产品推荐

