原因
由于数据库中的字符集为UTF-8
,所以插入emoji标签会报错
这是因为MySQL中的
utf8
编码只有三个字节,是虚假的UTF8,而emoji是占用4个字节的,所以会导致插入报错。同理,插入其他占用四个字节的字符也会报错,只不过平时接触到的大部分都是占用三个字节而已。
Java中的异常信息如上所示。
数据库修改
上面也解释了原因是由于MySQL的字符集问题导致的,所以解决方法很简单,就是将字符集设置为utf8mb4。
utf8mb4
是MySQL中对utf8
的补充,占用四个字节,可以理解为真正的UTF8
保险起见,将对应库、表、以及该字段的字符集都修改为了utf8mb4
-- 修改数据库字符集:
ALTER DATABASE database_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
-- 修改表的字符集:
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 修改某个字段字符集:
ALTER TABLE table_name CHANGE column_name VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
修改数据库连接
Java代码修改
此时在数据库中直接执行sql已经不会报错了,但是通过后台接口调用时,依然报错。
这是因为在通过jdbc连接后,字符集依然被设置为了utf8
,需要预先执行SET NAMES utf8mb4
才可以。
此时也想到了,既然可以再jdbc.url中指定
useUnicode=true&characterEncoding=utf8
,那么是否可以直接写成utf8mb4
呢?遗憾的是尝试没有成功,依然报错。
最开始通过jdbc直接连接,代码如下:
PreparedStatement preparedStatement1 = connection1.prepareStatement("SET NAMES utf8mb4");
preparedStatement1.execute();
PreparedStatement preparedStatement = connection1.prepareStatement("update common_user set user_name = ? where id = 47");
preparedStatement.setString(1, userName);
preparedStatement.execute();
这样子是没有报错的,可以正常执行。
然后将其修改为druid
的配置就大功告成了。
spring.datasource.druid.connection-init-sqls: SET NAMES utf8mb4
# 新版本druid也可能是init-connection-sqls
如果是在代码中手动配置的数据源,需要作如下修改:
DruidDataSource datasource = new DruidDataSource();
// 其余配置省略
List<String> sqls = new ArrayList<>();
sqls.add("SET NAMES utf8mb4");
datasource.setConnectionInitSqls(sqls);
MySQL配置
使用此方法时注意不要在jdbc url中写characterEncoding
使用此方法时注意不要在jdbc url中写characterEncoding
使用此方法时注意不要在jdbc url中写characterEncoding
修改内容如下,修改好以后,重启MySQL即可
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
验证
再次尝试,发现已经可以执行成功了。