java.sql.SQLException: Incorrect string value: '\xF0\x9F\x92\x9C' for column 'content' at row 1

产生这种异常的原因在于,mysql中的utf8编码最多会用3个字节存储一个字符,如果一个字符的utf8编码占用4个字节(最常见的就是emoji表情字符),那么在写入数据库时就会报错。

mysql从5.5.3版本开始,才支持4字节的utf8编码,编码名称为utf8mb4(mb4的意思是max bytes 4),这种编码方式最多用4个字节存储一个字符。

要想证明这个问题,可以执行以下sql:

select * from
information_schema.CHARACTER_SETS
where CHARACTER_SET_NAME like 'utf8%'

因此,要解决上述异常的发生,需要使用utf8mb4编码

解决完数据库编码后,如果还发生乱码问题或者在客户端执行sql没问题,但是在代码执行中依旧抱乱码错误,那么还需要解决客户端Connection连接对象使用的编码问题。

执行以下sql:

--查看mysql连接客户端的字符编码
show variables like 'char%'

 可以看出客户端Connection连接对象使用的编码是utf8mb4

解决:

//调用创建的Connection对象执行以下sql:
conn.createStatement().execute("SET names 'utf8mb4'");

如果项目中使用了DataSource数据源,只需要对数据源进行相关配置即可,这里以druid为例讲解,在spring框架下配置如下:

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://xxxxx" />
        <property name="username" value="username" />
        <property name="password" value="password" />
        <!-- 配置初始化大小、最小、最大 -->
        <property name="initialSize" value="8"/>
        <property name="maxIdle" value="2" />
        <property name="maxActive" value="150" />
        <!-- 配置获取连接等待超时的时间 -->
        <property name="maxWait" value="30000"/>
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="8000"/>
        <!-- 连接最小存活时间,最新活跃时间开始计算,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="5000"/>
        <property name="validationQuery" value="SELECT 'x'"/>
        <property name="testWhileIdle" value="true"/>
        <!-- 申请连接时检查连接有效性,验证不通过则会直接关闭该连接,并重新从连接池获取下一条连接 -->
        <property name="testOnBorrow" value="true"/>
        <property name="testOnReturn" value="true"/>
        <!-- 打开PSCache,并且指定每个连接上PSCache的大小-->
        <property name="poolPreparedStatements" value="false"/>
        <property name="maxPoolPreparedStatementPerConnectionSize" value="20"/>
        <!-- 此配置用于在创建Connection对象时执行指定的初始化sql -->
        <property name="connectionInitSqls">
            <list>
                <value>set names 'utf8mb4'</value>            
            </list>
        </property>    
</bean>

springboot自行对应修改,就不贴了

配置执行完此sql语句后,通过此连接对象后续创建的Statement都会成功地执行了。

引用自mysql参考手册

SET NAMES 'charset_name'

SET NAMES显示客户端发送的SQL语句中使用什么字符集。

因此,SET NAMES 'utf8mb4'语句告诉服务器:“将来从这个客户端传来的信息采用字符集utf8mb4”。它还为服务器发送回客户端的结果指定了字符集。(例如,如果你使用一个SELECT语句,它表示列值使用了什么字符集。)

SET NAMES 'x'语句与这三个语句等价:

mysql> SET character_set_client = x;

mysql> SET character_set_results = x;

mysql> SET character_set_connection = x;

 

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐