mysql客户端字符集_设置MySQL客户端连接使用的字符集

当一个客户端连接时,它向服务器发送希望使用的字符集名称,服务器把变量character_set_client、character_set_results和character_set_connection设置为该字符集,即实际上服务器为使用该字符集执行一个SET NAMES操作。

对于mysql客户端,如果你希望使用与默认字符集不同的字符集,不需要每次启动时执行SET NAMES语句,那么可以在mysql语句行中或者选项文件中添加一个--default-character-set选项设置。例如,你每次运行mysql时,以下的选项文件设置把三个字符集变量修改为koi8r:

[mysql]

default-character-set=koi8r

例如:假设column1定义为CHAR(5) CHARACTER SET latin2。如果没有设定SET NAMES或SET CHARACTER SET,那么对于SELECT column1 FROM t,当连接后,服务器使用客户端指定的字符集(即character_set_client声明的字符集)返回列column1的所有值。另一方面,如果你设定SET NAMES 'latin1'或SET CHARACTER SET latin1,那么发送结果之前,服务器转换latin2值到latin1。转换可能会丢失那些不属于两种字符集的字符。如果不希望服务器执行任何转换,设置character_set_results为NULL:

mysql> SET character_set_results = NULL;

下面我来做实验来证明上面所说的内容。

首先,用chcp命令可以查询到自己的cmd客户端是什么编码格式:

C:\Documents and Settings\shengtong>chcp

活动的代码页: 936 -- 936就是表示gbk的编码的意思

然后,在gbk编码对照表中,查询出汉字“中”的编码是D6D0。至此,已经清楚cmd客户端的字符集和汉字“中”gbk编码了。

第一个实验,我们保证character_set_client变量和character_set_connect变量一样,即保证声明的客户端和服务器是一样的编码,这样字符串传到服务器的时候就不需要转换,然后将字符串存储下来。

mysql> create table t (a varchar(100),b varchar(20),c int) default character set=gbk; -- 创建一个最终以gbk字符集存储数据的表t

Query OK, 0 rows affected (0.06 sec)

mysql> set names 'gbk'; -- 在服务器中“声明告知”客户端的字符集的“实情”,即character_set_client变量通过set names设置为gbk

Query OK, 0 rows affected (0.00 sec)

mysql> insert into t values('中','gbk',1);

Query OK, 1 row affected (0.05 sec)

mysql> select a,b,c,hex(a),hex('中') from t;

+------+------+------+--------+-----------+

| a | b | c | hex(a) | hex('中') | -- hex(a)列显示了表字段a的存储格式,hex('中')显示了gbk编码格式

+------+------+------+--------+-----------+

| 中 | gbk | 1 | D6D0 | D6D0 |

+------+------+------+--------+-----------+

1 row in set (0.00 sec)

这里可以清楚的看到表t正确的存储了汉字“中”,同时也表名了“中”的gbk编码为D6D0。解释一下这个过程,客户端字符集是gbk,然后其通过set names想server声明其字符集为gbk,并且底层表的字符集也是gbk,故一路下来在字符串的穿梭中没有发生任何字符集的转换,其最终在表t中正确的存储了汉字中,并且是正确的编码D6D0。查询时,同样字符串从存储引擎到server到客户端的传递游离中并没有发生字符集的转换,一切都可以正确显示出来。

mysql> set names 'latin1'; -- 对服务器“隐瞒”客户端字符集的“真实面目”,声明了一个错误的character_set_client变量为latin1

Query OK, 0 rows affected (0.00 sec)

mysql> insert into t values('中','latin1',2);

Query OK, 1 row affected, 1 warning (0.03 sec)

mysql> show warnings;

+---------+------+------------------------------------------------------------+

| Level | Code | Message |

+---------+------+------------------------------------------------------------+

| Warning | 1366 | Incorrect string value: '\xD6\xD0' for column 'a' at row 1 |

+---------+------+------------------------------------------------------------+

1 row in set (0.00 sec)

mysql> select a,b,c,hex(a),hex('中') from t;

+------+--------+------+--------+-----------+

| a | b | c | hex(a) | hex('中') |

+------+--------+------+--------+-----------+

| ? | gbk | 1 | D6D0 | D6D0 |

| ?? | latin1 | 2 | 3F3F | D6D0 |

+------+--------+------+--------+-----------+

2 rows in set (0.00 sec)

mysql> create table t1 ( a varchar(10)) default character set=utf8;

Query OK, 0 rows affected (0.06 sec)

mysql> set names latin1;

Query OK, 0 rows affected (0.00 sec)

mysql> insert into t1 values('中');

Query OK, 1 row affected (0.00 sec)

通过SET NAMES,客户端向服务器声明它使用的是latin1字符集,但实际上它欺骗了它,它实际上上是gbk字符集。由于character_set_client和character_set_connection两个变量相同,故在server中他们是不需要转换的,故hex('中')的值仍然是D6D0。由于表的字符集是gbk,故当存储数据的时候就会发生一次字符集的编码映射转换。转换的过程是这样的,由于latin1是单字节编码字符集,那么传过来的两个字节0xD6和0xD0,会根据其在latin1中对应的“字”,然后转到相应的gbk编码的“字”,然后根据这个gbk字编码存储起来。在转换发生时,发现latin1字符集中的0xD6和0xD0在gbk找不到对应的字,故报warnings,无法完成转换,那么就只有插入个无意义的“字”,故就用gbk编码的无意义字0x3F存储了起来(?的编码在所有字符集中都是0x3F,而且对某个字符集不能表示的编码所对应的字符就用?)。但是在utf8的编码表中latin1编码为D6和D0的“字”能够正确表示,故能将他们存储起来。

解释一下,为什么不能正确查看c=1的这行记录。因为这里通过set names已经将character_set_results设置为latin1了,故数据从表中出来以后,会做一层转换,从gbk转到latin1。转换时,发现“中”在latin1中无法显示,故以0x3F编码的?来显示了。

接下来接着验证一下latin1和gbk中0xD6和0xD0是什么字符,?的编码等:

mysql> select _latin1 x'D6';

+---------------+

| _latin1 x'D6' |

+---------------+

| ? |

+---------------+

1 row in set (0.01 sec)

mysql> select _latin1 x'D0';

+---------------+

| _latin1 x'D0' |

+---------------+

| ? |

+---------------+

1 row in set (0.00 sec)

mysql> set names 'gbk';

Query OK, 0 rows affected (0.00 sec)

mysql> select hex('?');

+----------+

| hex('?') |

+----------+

| 3F |

+----------+

1 row in set (0.03 sec)

mysql> set names 'latin1';

Query OK, 0 rows affected (0.00 sec)

mysql> select hex('?');

+----------+

| hex('?') |

+----------+

| 3F |

+----------+

1 row in set (0.00 sec)

以上转换过程,看看在变成字节编码的utf8中是不是也是根据我们所阐述的发生着转换。在utf8中,汉字的编码都是3个字节编码的:

mysql> set names 'utf8';

Query OK, 0 rows affected (0.00 sec)

mysql> insert into t values('中','utf8',3);

Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> show warnings;

+---------+------+------------------------------------------------------------+

| Level | Code | Message |

+---------+------+------------------------------------------------------------+

| Warning | 1366 | Incorrect string value: '\xD6\xD0' for column 'a' at row 1 |

+---------+------+------------------------------------------------------------+

1 row in set (0.14 sec)

mysql> select a,b,c,hex(a),hex('中') from t;

+------+--------+------+--------+-----------+

| a | b | c | hex(a) | hex('中') |

+------+--------+------+--------+-----------+

| 涓? | gbk | 1 | D6D0 | D6D0 |

| ?? | latin1 | 2 | 3F3F | D6D0 |

| ? | utf8 | 3 | 3F | D6D0 |

+------+--------+------+--------+-----------+

3 rows in set (0.00 sec)

mysql> select _utf8 x'D6D0D3'; -- 这里说明0xD6D0在utf8中是无法显示的编码,故其最终以字符“?”代替,且就一个,那么存到gbk编码中就说一个0x3f编码的?了。

ERROR 1300 (HY000): Invalid utf8 character string: 'D6D0D3'

上面这个实验已经很好的说明了mysql中字符集之间的映射转换过程,整个实验是保证character_set_client和character_set_connection、character_set_results一样来完成的,那么如果他们不一样呢?

请看实验二:

mysql> set names 'gbk';

Query OK, 0 rows affected (0.00 sec)

mysql> select hex('中');

+-----------+

| hex('中') |

+-----------+

| D6D0 |

+-----------+

1 row in set (0.00 sec)

mysql> set character_set_client=latin1;

Query OK, 0 rows affected (0.00 sec)

mysql> set character_set_connection=utf8;

Query OK, 0 rows affected (0.00 sec)

mysql> set character_set_results=gbk;

Query OK, 0 rows affected (0.00 sec)

mysql> select hex('中');

+-----------+

| hex('??') |

+-----------+

| C396C390 |

+-----------+

1 row in set (0.02 sec)

mysql> set character_set_results=latin1;

Query OK, 0 rows affected (0.00 sec)

mysql> select hex('中');

+-----------+

| hex('中') |

+-----------+

| C396C390 |

+-----------+

1 row in set (0.00 sec)

latin1编码为0xd6和0xd0对应的utf8编码为0xc396和0xc390,client到connection完成了正确的转换,而hex函数返回的结果都是英文字母和数字,故不论results设置成什么,结果都是c396c390。

实验三,再来看看character_set_results参与的转换:

mysql> set character_set_client=latin1;

Query OK, 0 rows affected (0.00 sec)

mysql> set character_set_connection=utf8;

Query OK, 0 rows affected (0.00 sec)

mysql> set character_set_results=latin1;

Query OK, 0 rows affected (0.00 sec)

mysql> select '中';

+----+

| 中 |

+----+

| 中 |

+----+

1 row in set (0.00 sec)

latin1编码的0xD6D0从client被转换到connection的utf8编码,结果为0xC396C390,返回时,又从0xC396C390转换到0xD6D0。而0xD6D0,刚好能正确显示汉字“中”。

mysql> set character_set_results=utf8;

Query OK, 0 rows affected (0.00 sec)

mysql> select '中';

+------+

| 脰脨 |

+------+

| 脰脨 |

+------+

1 row in set (0.00 sec)

由于connection和results是一样的,故不转换,那么汉字编码为0xC396C390的汉字“脰脨”就被显示了出来。

mysql> set character_set_results=gbk;

Query OK, 0 rows affected (0.00 sec)

mysql> select '中';

+----+

| ?? |

+----+

| ?? |

+----+

1 row in set (0.00 sec)

utf8编码为0xC396C390的字符在gbk中没有对应的“字”,故connection到results的转换不成功,以乱码表示了。

mysql> set character_set_results=null;

Query OK, 0 rows affected (0.00 sec)

mysql> select '中';

+------+

| 脰脨 |

+------+

| 脰脨 |

+------+

1 row in set (0.00 sec)

屏蔽了connection到results的转换,故最终显示gbk编码为0xC396C390的两个字“脰脨”

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值