今天遇到一个Mysql插入用户信息时报错的问题,报错信息如下
java.sql.SQLException: Incorrect string value: '\xF0\x9F\x90\xB8' for column 'userName' at row 1
原因是用户的userName这里录入了emoji表情🐷,而要插入的表中定义的字符集是utf8。
mysql的utf8编码的一个字符最多3个字节,但是一个emoji表情为4个字节,所以utf8不支持存储emoji表情。
但是utf8的超集utf8mb4一个字符最多能有4字节,所以能支持emoji表情的存储。
我们针对数据库层面全部设置的都是utf8mb4,这有这个表和与之关联的另外两个表才是设置的utf8,所以我们的修改策略是修改这三张表的字符集。
ALTER TABLE 表名 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
但是这种修改方式有一个前提,就是这几张表中是没有历史数据的。如果在更改字符集之前已经存在了历史数据,那么只修改表的字符集的话只会对修改之后新插入的varchar类型数据以utf8mb4进行存储,而之前的记录还是以utf8的形式存储的,这样就造成了一张表中同一个字段既有utf8也有utf8mb4两种编码类型,那么显然这种在生产环境是不允许出现的。
为了避免这个问题,我们需要把这张表里面的所有的varchar类型的字段设置成utf8mb4同时也把表设置成utf8mb4,放在一个ALTER语句中一次更新,避免重复锁表。
ALTER TABLE 表名 CHANGE 字段名 字段名 该字段原来的数据类型 CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
一张表修改完了,也要确保与之相关的其他表的字段也需要更新为utf8mb4。比如A表作为主表你已经把唯一主键code改成了utf8mb4,而与之关联的明细表B中的关联字段code还是utf8,那么如果有之前代码里面有join语句的话,因为字符集不一样,那么是不会走索引的。所以变更字符集时也需要留意相关表的字符集是否一致。