【发布时间】:2018-02-17 08:13:32
【问题描述】:
今天,一位java工程师来找我,告诉我一个错误:
select * from some_table where name=? ...
### Cause: java.sql.SQLException: Illegal mix of collations (utf8mb4_unicode_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '='
默认字符集为 utf8,collate 为 utf8_general_ci,列名的字符集为 utf8mb4,collate 为 utf8mb4_unicode_ci,列 'name' 的值为 utf8mb4 值(包括表情符号)。
于是我检查了数据库配置,发现:
character_set_client=utf8
character_set_connection=utf8
character_set_server=utf8
所以,我认为修复这个错误很容易:
set global character_set_server=utf8mb4;
set global collation_server=utf8mb4_unicode_ci;
set global init_connect='SET NAMES utf8mb4'
但是重启java程序后,错误依旧! 于是我在MySQL服务器中开启了通用日志,发现SQL语句很奇怪:
4584243 Connect some_user@10.17.1.100 on some_database
4584243 Query SET NAMES utf8mb4 # this is the result for the init_connect.
Query /* mysql-connector-java-5.1.35 ( Revision:
5fb9c5849535c13917c2cf9baaece6ef9693ef27 ) */SHOW VARIABLES WHERE
Variable_name ='language' OR Variable_name = 'net_write_timeout' OR
Variable_name = 'interactive_timeout' OR Variable_name = 'wait_timeout' OR
Variable_name = 'character_set_client' OR Variable_name =
'character_set_connection' OR Variable_name = 'character_set' OR
Variable_name = 'character_set_server' OR Variable_name = 'tx_isolation' OR
Variable_name = 'transaction_isolation' OR Variable_name =
'character_set_results' OR Variable_name = 'timezone' OR Variable_name =
'time_zone' OR Variable_name = 'system_time_zone' OR Variable_name =
'lower_case_table_names' OR Variable_name = 'max_allowed_packet' OR
Variable_name = 'net_buffer_length' OR Variable_name = 'sql_mode' OR
Variable_name = 'query_cache_type' OR Variable_name = 'query_cache_size' OR
Variable_name = 'license' OR Variable_name = 'init_connect'
4584243 Query /* mysql-connector-java-5.1.35 ( Revision:
5fb9c5849535c13917c2cf9baaece6ef9693ef27 ) */SELECT
@@session.auto_increment_increment
4584243 Query SELECT @@session.autocommit
4584243 Query SET NAMES utf8 # Who issued this?
4584243 Query SET character_set_results = NULL
4584243 Query SET autocommit=1
4584243 Query select @@session.tx_read_only
4584243 Query SELECT @@session.tx_isolation
4584243 Query select * from some_table where name = 'xxxx' # OK, now normal business SQL statement starts
可以清楚的看到有一条SQL:
4584243 Query SET NAMES utf8 # JDBC issued this
此 SQL 导致我的修复失效。谁或什么框架会发出这种SQL,如何禁用它?
欢迎提出任何建议。
更新: 我认为这不是 JDBC 而是 MySQL 服务器导致了这个问题,因为当我使用本机 JDBC 连接到具有 init_connect='set names utf8mb4' 的另一台服务器时,客户端连接的字符集正确设置为 utf8mb4,我不知道为什么它不起作用这个 MySQL 服务器。两台服务器的字符集和排序规则配置相同。
更新: 我重新启动 MySQL 服务器后,问题就消失了!连接器 J 或 MySQL 服务器中可能存在错误,因为文档说 character_set_server 和 collation-server 是动态选项,但实际上并非所有客户端都如此:它适用于本机 mysql 客户端,但不适用于连接器 J。
【问题讨论】:
-
mysql中也有正常设置“utf8”的连接字符串。