在执行mysql client.For中的sql命令时,我使用java程序模拟字符集转换示例:
mysql> show variables like 'character%';
+--------------------------+---------------------------------------+
| Variable_name | Value |
+--------------------------+---------------------------------------+
| character_set_client | gbk |
| character_set_connection | latin1 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | gbk |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| character_sets_dir | /opt/mysql/server-5.6/share/charsets/ |
+--------------------------+---------------------------------------+
mysql> show create table t4\G
*************************** 1. row ***************************
Table: t4
Create Table: CREATE TABLE `t4` (
`data` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
mysql> insert into t4 select '\U+1F600';
mysql> select data,hex(data) from t4;
+------+-----------+
| data | hex(data) |
+------+-----------+
| ?? | 3F3F |从mysql文档(https://dev.mysql.com/doc/refman/5.0/en/charset-connection.html)中,数据似乎首先从os字符集(Utf8)转换为客户端(Gbk),然后从gbk(客户端)转换为latin1(连接)。因此,基于以上理解,我编写了一个java测试程序来模拟这种看不见的转换。如下所示:
/**
* os utf-8
* character_set_client gbk
* character_set_connection latin1
* field latin1
*
* @throws UnsupportedEncodingException
*/
@Test
public void test_os_utf8_to_client_gbk_to_connection_latin1() throws UnsupportedEncodingException{
String emoji = "";
String receivedStr = new String(emoji.getBytes("utf-8"),"gbk"); //os(utf-8)-->client(gbk)
System.out.println(receivedStr);//馃榾
String convertedStr = new String(receivedStr.getBytes("latin1"),"latin1"); //client(gbk) --> connection(latin1)
System.out.println(convertedStr);//??
printHexString(convertedStr.getBytes("latin1")); //3f 3f}
上面的代码可以得到与实际mysql操作相同的结果。我想知道这个模拟背后的原则是正确的还是碰巧是正确的?
发布于 2015-05-15 07:48:55
是4字节的utf8字符。在MySQL中,它需要CHARACTER SET utf8mb4,而不是utf8。(外界称它为utf8或UTF-8,但MySQL有一个区别。)
\U+1F600还说,它在utf8中将是4个字节,因为它比FFFF大。
可以在MySQL的utf8或utf8mb4中呈现馃榾。它是十六进制的E9A683 E6A6BE。
对于这两种情况,latin1都不是一个好的MySQL CHARACTER SET。它可以使用(尽管不是您尝试的方式),但这只是因为latin1无法检查字节的有效性。所有8位的值在latin1中都有一定的意义。但是,对于表情符号,您可能会获得😀,对于这对中文字符,您可能会获得馃榾。
混合使用六个character%设置简直是自找麻烦。尝试从默认设置开始,然后使用SET NAMES恰好更改其中的三个。这3个是_client、_connection和_results。
问号出现的原因是:
SET NAMES latin1 in in(默认,但错误)CHARACTER SET latin1 (默认,但错误)无法从表中检索数据。
为了做正确的事情,
CHARACTER SET utf8mb4utf8mb4在从客户端到服务器的连接中,<meta...charset=utf-8>应该在顶部附近。(其中两个指定了utf8mb4,因为它们与MySQL对话;另外两个是更通用的utf8。)
你提到了gbk。如果客户端中的字节被编码为"gbk",则继续本段。(我怀疑它们不是,因为Java喜欢处理Unicode,所以是utf8。)如果您已经建立了SET NAMES gbk,那么在客户端中使用gbk字节是可以的。这意味着gbk编码的字节将在表的CHARACTER SET之间进行代码转换。注意:latin1不能容纳中文字符,也不能容纳表情符号,因此CHARACER SET latin1不是一个有效的对象。CHARACTER SET gbk或utf8mb4应该可以工作。(此外,我怀疑gbk不能使用这个表情符号,所以utf8mb4可能是唯一合理的选择,而SET NAMES gbk可能无法工作。)
https://stackoverflow.com/questions/30233739
复制相似问题