mysql连接通道中的字符集和校验规则

您所在的位置:网站首页 mysql数据校验 mysql连接通道中的字符集和校验规则

mysql连接通道中的字符集和校验规则

2022-03-25 01:08| 来源: 网络整理| 查看: 265

这里首先需要解释的是,我想应该就是连接通道的含义了。那什么是连接通道呢?

所谓连接通道,就是客户端和服务器端保持连接的一个通道,它是逻辑上的一个概念。客户端通过连接通道发送sql语句到服务器端,服务端执行,将结果再通过连接通道返回至客户端。the connection is the pass when you connect to the server.

这个过程中,有几个临界点(逻辑上概念),是我们需要注意的,mysql也就在这几个临界点上做了文章。

1、当语句离开客户端的时候: 从客户端出来的,包括sql语句本身(这里里面就包含字符串和关键字等了),以及character_set_client系统变量。为什么要包含这个变量呢?这个变量的作用说明2点,也是它的作用:一是表示该语句中的字符集是使用character_set_client指定的字符集编码的,二是通过此系统变量来告诉服务器所发送来的语句中的字符集编码。 2、当服务器端接受到客户端的语句的时候: mysql会使用character_set_connection/collation_connection指定的字符集以及校验规则,将客户端的字符串,做一个从character_set_client到character_set_connection的转换。 3、当服务器处理好结果以后,在把结果传给客户端前: mysql会先将结果转换成character_set_results指定的字符集,然后传回给客户端。

当字符串在mysql服务器的时候,最终以什么格式存储到mysql数据库中,这个是受到具体的数据表级别、列级别字符集设置的控制了。

从上面的介绍中,我们就知道和连接通道相关几个参数了,他们分别是character_set_client/connection/results,可以如下查看:

mysql> show variables like ‘char%’; +————————–+——————-+ | Variable_name | Value | +————————–+——————-+ | character_set_client | latin1 | | character_set_connection | latin1 | | character_set_database | gbk | | character_set_results | latin1 | | …………………….| …… | +————————–+——————-+ 8 rows in set (0.00 sec) mysql> show variables like ‘colla%’; +———————-+——————-+ | Variable_name | Value | +———————-+——————-+ | collation_connection | latin1_swedish_ci | | collation_database | gbk_bin | | collation_server | latin1_swedish_ci | +———————-+——————-+ 3 rows in set (0.00 sec)

下面我们来做个实验,来证明一下这个结果:

首先保证character_set_connection与character_set_results以及底层存储字符集的一致性,看看character_set_client的效果。

mysql> show variables like ‘char%’; +————————–+——————+ | Variable_name | Value | +————————–+——————+ | character_set_client | latin1 | | character_set_connection | gbk | | character_set_database | gbk | | character_set_results | gbk | | …………………….| …… | +————————–+——————+ 8 rows in set (0.00 sec) mysql> create table t (a varchar(10)); — 这里没有指定字符集,就默认使用了database的字符集gbk了 Query OK, 0 rows affected (0.08 sec)

mysql> insert into t values(‘中国’); Query OK, 1 row affected (0.00 sec)

mysql> select * from t; +——-+ | a | +——-+ | ???ú | +——-+ 1 row in set (0.00 sec)

通过以上的介绍,所以为了防止出现乱码,我们可以把character_set_client,character_set_connection,character_set_database,character_set_results设置成同样的值,把collation_connection和collation_database也设置成同样的值,这样就“一劳永逸”了。程序连接mysql的时候,一般都会显示设置character_set_client的值,如java连接中,一般都有如下的一段代码来显示设置这个值: 由此可以看到由于latin1与gbk对汉字的编码方式不一样(或者说latin1根本就不能正确编码汉字),在这个collection过程中,从character_set_client到character_set_connection转换时,就把你输入的好好的汉字转换成乱码了。那么,如果让过程不发生转换呢?

mysql> set character_set_client=gbk; Query OK, 0 rows affected (0.00 sec) mysql> insert into t values(‘人民’); Query OK, 1 row affected (0.02 sec)

mysql> select * from t; +——-+ | a | +——-+ | ???ú | | 人民 | +——-+ 2 rows in set (0.00 sec)

可见,这里是能正确存储和显示的,很简单,因为任何转换都没有发生,当然就不会出现乱码了。

接着做实验,我们让character_set_connection发生变化:

mysql> set character_set_connection=latin1; Query OK, 0 rows affected (0.00 sec) mysql> insert into t values (‘共和国’); Query OK, 1 row affected (0.00 sec)

mysql> select * from t; +——-+ | a | +——-+ | ???ú | | 人民 | | ??? | +——-+ 3 rows in set (0.00 sec)

可见,这里character_set_client=gbk,character_set_connection=latin1,character_set_database=gbk。首先,client到connection过程中,汉字被转换成乱码(这个过程可能就会丢失信息);然后存储数据的时候,又从connection到存储的字符集(gbk)发生一次转换,乱码被转换成“更”乱码。这里如果connection与client的字符集有种包容性关系的话,如character_set_client=gbk, character_set_connection=utf8,character_set_results=gbk,底层存储也是gbk编码,由于utf8“兼容”所有的字符集,故在转换过程中不会发生信息丢失,查询的时候也不会是乱码,如下:

mysql> show variables like ‘char%’; +————————–+—————–+ | Variable_name | Value | +————————–+—————–+ | character_set_client | gbk | | character_set_connection | utf8 | | character_set_database | gbk | | character_set_results | gbk | | …………………….| …… | +————————–+—————–+ 8 rows in set (0.00 sec) mysql> create table t (a varchar(10)) Query OK, 0 rows affected (0.05 sec)

mysql> insert into t values(‘中国’); Query OK, 1 row affected (0.00 sec)

mysql> select * from t; +——+ | a | +——+ | 中国 | +——+ 1 rows in set (0.00 sec)

我来解释一下这个过程,假设“中国”的gbk编码是1234,而utf8的编码是4321,utf8的编码为1234的假设是“淘宝”。client的“中国”的编码1234进入connection,仍然是1234(但实际上它的含义已经发生变化为“淘宝”),存储的时候connection的1234编码到表存储也是1234,刚好正确表达了“中国”的意思,查询返回时,由于results也是gbk,所以不发生转换,正确显示。很显然,如果results又是一种与gbk不兼容的字符集如latin1,查询又会出问题,如下:

mysql> set character_set_results=latin1; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; +——+ | a | +——+ | ?? | +——+ 1 rows in set (0.00 sec)

当我们改变底层存储的字符集的时候,会怎样?请看如下实验:

mysql> show variables like ‘char%’; +————————–+—————+ | Variable_name | Value | +————————–+—————+ | character_set_client | gbk | | character_set_connection | gbk | | character_set_database | gbk | | character_set_results | gbk | | …………………….| …… | +————————–+—————+ 8 rows in set (0.01 sec) mysql> create table t (a varchar(10)) charset=latin1; Query OK, 0 rows affected (0.05 sec)

mysql> insert into t values(‘淘宝’); Query OK, 1 row affected, 1 warning (0.02 sec)

mysql> select * from t; +——+ | a | +——+ | ?? | +——+ 1 row in set (0.00 sec)

mysql> show variables like ‘char%’; +————————–+————-+ | Variable_name | Value | +————————–+————-+ | character_set_client | latin1 | | character_set_connection | latin1 | | character_set_database | gbk | | character_set_results | latin1 | | ………………….. | …… | +————————–+————-+ 8 rows in set (0.00 sec) mysql> show variables like ‘collat%’; +———————-+——————-+ | Variable_name | Value | +———————-+——————-+ | collation_connection | latin1_swedish_ci | | collation_database | gbk_bin | | collation_server | latin1_swedish_ci | +———————-+——————-+ 3 rows in set (0.00 sec)

mysql> set character set ‘ascii’; Query OK, 0 rows affected (0.00 sec)

mysql> show variables like ‘char%’; +————————–+————-+ | Variable_name | Value | +————————–+————-+ | character_set_client | ascii | | character_set_connection | gbk | | character_set_database | gbk | | character_set_results | ascii | | ………………….. | …… | +————————–+————-+ 8 rows in set (0.00 sec)

mysql> show variables like ‘collat%’; +———————-+——————-+ | Variable_name | Value | +———————-+——————-+ | collation_connection | gbk_bin | | collation_database | gbk_bin | | collation_server | latin1_swedish_ci | +———————-+——————-+ 3 rows in set (0.00 sec)

很显然,由于latin1字符集无法存储汉字,故出现乱码。

下面,我们只改变results字符集,看看效果如何:

mysql> show variables like ‘char%’; +————————–+—————-+ | Variable_name | Value | +————————–+—————-+ | character_set_client | gbk | | character_set_connection | gbk | | character_set_database | gbk | | character_set_results | latin1 | | …………………….| …… | +————————–+—————-+ 8 rows in set (0.00 sec) mysql> create table t (a varchar(10)) charset=gbk; Query OK, 0 rows affected (0.08 sec)

mysql> insert into t values(‘淘宝’); Query OK, 1 row affected (0.00 sec)

mysql> select * from t; +——+ | a | +——+ | ?? | +——+ 1 row in set (0.00 sec)

这里collation_connection = @@collation_database的意思就是把collation_connection的设置的collation_database的值,由于collation肯定能确定character set,故其又相当于多做了个设置:把character_set_connetion设置成character_set_database的值。请看如下实验: 很显然,底层为gbk编码的字符串转换成latin1的字符集的字符,变成乱码,传给客户端,再次转换成gbk字符集,变成“更”乱码,故显示乱码。

下面,我再介绍几个“简约”命令。 SET NAMES ‘x’,(SET NAMES ‘charset_name’ COLLATE ‘collation_name’)相当于:

SET character_set_client = x; SET character_set_results = x; SET character_set_connection = x;

实验如下:

mysql> show variables like ‘char%’; +————————–+—————-+ | Variable_name | Value | +————————–+—————-+ | character_set_client | gbk | | character_set_connection | gbk | | character_set_results | latin1 | | …………………….| …… | +————————–+—————-+ 8 rows in set (0.00 sec) mysql> set names ‘ascii’; Query OK, 0 rows affected (0.00 sec)

mysql> show variables like ‘char%’; +————————–+—————-+ | Variable_name | Value | +————————–+—————-+ | character_set_client | ascii | | character_set_connection | ascii | | character_set_results | ascii | | …………………….| …… | +————————–+—————-+

SET CHARACTER SET ‘x’,相当于:

SET character_set_client = x; SET character_set_results = x; SET collation_connection = @@collation_database;

这里collation_connection = @@collation_database的意思就是把collation_connection的设置的collation_database的值,由于collation肯定能确定character set,故其又相当于多做了个设置:把character_set_connetion设置成character_set_database的值。请看如下实验:

mysql> show variables like ‘char%’; +————————–+————-+ | Variable_name | Value | +————————–+————-+ | character_set_client | latin1 | | character_set_connection | latin1 | | character_set_database | gbk | | character_set_results | latin1 | | ………………….. | …… | +————————–+————-+ 8 rows in set (0.00 sec) mysql> show variables like ‘collat%’; +———————-+——————-+ | Variable_name | Value | +———————-+——————-+ | collation_connection | latin1_swedish_ci | | collation_database | gbk_bin | | collation_server | latin1_swedish_ci | +———————-+——————-+ 3 rows in set (0.00 sec)

mysql> set character set ‘ascii’; Query OK, 0 rows affected (0.00 sec)

mysql> show variables like ‘char%’; +————————–+————-+ | Variable_name | Value | +————————–+————-+ | character_set_client | ascii | | character_set_connection | gbk | | character_set_database | gbk | | character_set_results | ascii | | ………………….. | …… | +————————–+————-+ 8 rows in set (0.00 sec)

mysql> show variables like ‘collat%’; +———————-+——————-+ | Variable_name | Value | +———————-+——————-+ | collation_connection | gbk_bin | | collation_database | gbk_bin | | collation_server | latin1_swedish_ci | +———————-+——————-+ 3 rows in set (0.00 sec)

通过以上的介绍,所以为了防止出现乱码,我们可以把character_set_client,character_set_connection,character_set_database,character_set_results设置成同样的值,把collation_connection和collation_database也设置成同样的值,这样就“一劳永逸”了。程序连接mysql的时候,一般都会显示设置character_set_client的值,如java连接中,一般都有如下的一段代码来显示设置这个值:

jdbc:mysql://10.1.6.174:3306/notify?connectTimeout=1000&characterEncoding=utf8



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3