大家好呀,我是summo,这次的文章标题是一个Mysql数据库的SQL错误,遇到的同学自然懂,没遇到的同学希望你永远也不要遇到。
Cause: java.sql.SQLException: Incorrect string value: '\xF0\x9F\x90\xA6' for column 'name' at row 1
这个错误通常是由于数据库列的字符集设置不支持某些特殊字符(例如表情符号)
,导致在插入或更新数据时失败。根源就是MySQL使用的是utf8编码,utf8编码默认每个字符3个字节,而Emoji表情使用的Unicode编码占4个字节,所以写入数据库的时候会写入失败并报错。
有设计表结构经验的同学应该都知道MySQL的存储引擎,如InnoDB和MyISAM,但表的字符集不知道大家清不清楚。简单来说表的字符集(Character Set)决定了表中可以存储的字符类型及其编码方式。最适合存储表情符号的字符集是utf8mb4
,所以遇到这个错误时首先检查一下错误表的字符集。
SHOW VARIABLES LIKE 'character_set%';
SHOW CREATE TABLE sample_table;
如果检查后数据库字符集和表字符集都是
utf8mb4
,但是添加表情符号还是失败的话,那么跟数据库就没有关系了。
这一步也简单,就是确认spring.datasource.url
中是否也包含 utf8mb4
配置,如果没有的话,就加上useUnicode=true&characterEncoding=utf8mb4
,如:
spring.datasource.url=jdbc:mysql://localhost:3306/your_database_name?useUnicode=true&characterEncoding=utf8mb4
网上搜索的文章大部分都是这两个解决思路,有些甚至会让你去看MySQL的配置,修改后重新启动MySQL,但最终可能却并不能解决这个问题。如果你确定字符集是对的,数据库连接配置也是对的,但报错还是存在,那么就在执行SQL之前执行一次set names utf8mb4
语句。
如果你没有使用连接池,那么在调用SQL之前,需要手动执行一次set names utf8mb4
语句,如下:
conn = DriverManager.getConnection(url, user, password);
stmt = conn.createStatement();
stmt.execute("SET NAMES utf8mb4");
使用Druid连接池的话,那么可以直接加一行配置就行了,如下:
spring.datasource.druid.connection-init-sqls=set names utf8mb4
同Druid连接池,加一行配置就行了,如下:
spring.datasource.hikari.connection-init-sql=SET NAMES utf8mb4
其他连接池我就不列举了,大同小异。
set names utf8mb4
通过确保客户端、连接和服务器之间的数据传输在同一字符集下进行,从根本上避免了字符集不匹配的问题,所以执行该命令能够解决你插入表情符号时报错的问题。
当你执行 set names utf8mb4
语句时,它实际上做了以下几件事情:
设置客户端字符集:
使MySQL客户端的字符集为utf8mb4,这意味着客户端(也就是你的应用程序)发送给MySQL服务器的数据将被解释为utf8mb4格式。
设置连接字符集:
使数据库连接层(也叫连接字符集)的编码为utf8mb4。这保证了当数据在客户端和服务器之间传输时,被正确地编码和处理。
设置结果字符集:
使MySQL服务器返回给客户端的查询结果(比如SELECT语句的结果)都使用utf8mb4编码。
最初,我的记录方式更偏向简单的笔记,后来发现笔记太乱,为了提高查阅效率,我开始给每个部分加上标题和段落,这样它们就演变成了短文。随着时间的推移,我逐渐增加了内容的层次,加入了前因、详细的分析过程以及小结,这些改进使我的记录更加完善,最终变成了结构化的文章。
不过,在文章标题的选择上,我有些犹豫。尽管起一个吸引人的标题能让文章更有吸引力,但如果将来遇到类似的问题时,因为标题花哨、不明确而导致找不到解决方案,那就得不偿失了。
因所负责的系统使用的spring框架版本5.1.5.RELEASE在线上出过一个偶发的小事故,最后定位为spring-context中的一个bug导致的。