在执行单测时,碰到了以下熟悉的问题
org.springframework.jdbc.UncategorizedSQLException:
### Error updating database. Cause: java.sql.SQLException: Incorrect string value: '\xF0\x9F\x92\x8B' for column 'name' at row 1
### The error may involve com.***.insert-Inline
### The error occurred while setting parameters
### SQL: insert into **********************
### Cause: java.sql.SQLException: Incorrect string value: '\xF0\x9F\x92\x1B' for column 'name' at row 1
; uncategorized SQLException; SQL state [HY000]; error code [1366]; Incorrect string value: '\xF0\x9F\x92\x8B' for column 'name' at row 1; nested exception is java.sql.SQLException: Incorrect string value: '\xF0\x9F\x92\x8B' for column 'name' at row 1
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:89)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446)
at com.sun.proxy.$Proxy81.insert(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:278)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:58)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
at com.sun.proxy.$Proxy92.insertUser(Unknown Source)
乍一看就是emoji入库失败,应该是表的字符集设置有问题。于是打开sql工作台执行
show variables like '%character%';
执行结果
mysql> show variables like "%character%";
+--------------------------+----------------------------------------+
| Variable_name | Value |
+--------------------------+----------------------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/soft/mysql-5.6.31***** |
+--------------------------+----------------------------------------+
8 rows in set
看似没有问题,字符集是utf8mb4,在使用sql试试,发现执行成功。
把代码中报错的sql复制出来,到控制台上执行,还是成功。
这就很奇怪了,难道jdbc有什么问题?这个数据库之前就有保存emoji保存的业务,去线上库捞一下数据库配置。
mysql> show variables like "%character%";
+--------------------------+----------------------------------------+
| Variable_name | Value |
+--------------------------+----------------------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| character_sets_dir | /usr/soft/mysql-5.6.31***** |
+--------------------------+----------------------------------------+
8 rows in set
发现只有character_set_server配置有所不同,难不成这个配置还能影响字符集类型?
这个character_set_server的作用是什么呢?
查阅文章可知,character_set_server与jdbc连接有关系。
官方对 JDBC 驱动的说明如下:
JDBC client与Mysqlserver默认是自动进行检测的。如果服务器端指定了character_set_server变量, 则 JDBC 驱动会自动使用该字符集(在不指定 JDBC URL 参数characterEncoding和connectionCollation的情况下)。 可以通过characterEncoding (该参数值是使用 Java 风格的形式指定. 例如 UTF-8 )来进行手工指定, 而不是自动检测。 为了在 MySQL JDBC 驱动版本 5.1.46 及之前的版本中使用 utf8mb4, 则服务器端必须配置character_set_server=utf8mb4, 否则JDBC URL参数characterEncoding=UTF-8 表示的是 MySQL 的 utf8, 而不是 utf8mb4
联系dba修改数据库参数character_set_server,但是并没有重启数据库,dba表示库比较多,暂时不需要重启,是动态生效的(实际并不是😂)。
在dba要求下重启应用n次之后,终于答应我重启数据库服务。
直接成功,完结撒花。
最后还是看一下这个不生效的情况。。
Mysql JDBC 客户端 (Mysql Connector-j) 在不同的版本中对字符集的支持有一定差异。版本的分界线在 5.1.46 和 5.1.47 。
测试过程中,在重启 Server 情况下字符集都可以生效,而不重启 Server 的情况下只有 5.1.47 在客户端设置了字符集情况下才生效。具体情况如下表:
官方文档中提到, Server 端的 character_set_server=utf8mb4 设置完成后,客户端如果没有配置“ characterEncoding ”会使用服务端配置的 utf8mb4 字符集。
估计是之前测试库迁移,没有按照生产配置搞,害,没用的知识又增加了