前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MySQL字符集终极指南--进阶篇

MySQL字符集终极指南--进阶篇

原创
作者头像
DBA成江东
修改2023-08-14 18:52:32
1.4K0
修改2023-08-14 18:52:32
举报
文章被收录于专栏:数据库之巅数据库之巅

请先阅读上篇: MySQL字符编码指南--基础篇

1. 字符集四类设置

1.1 操作系统字符集

以下配置项是Linux系统的本地化(localization)设置,用于控制系统在不同方面如何呈现和处理数据。下面是每个配置项的解释:

代码语言:javascript
复制
[root@VM-94-230-centos ~]# locale

LANG=zh_CN.GBK: 设置系统的默认语言和字符集。在这里,zh_CN表示中国的简体中文,GBK是一种常用于简体中文的字符编码。
LC_CTYPE="zh_CN.GBK": 控制字符分类和字符串处理的规则,例如字母的大小写转换。
LC_NUMERIC="zh_CN.GBK": 控制数字的格式,例如数字的千位分隔符。
LC_TIME="zh_CN.GBK": 控制日期和时间的格式。
LC_COLLATE="zh_CN.GBK": 控制字符串排序的规则,例如在字典排序中如何比较字符。
LC_MONETARY="zh_CN.GBK": 控制货币格式,例如货币符号和货币值的格式。
LC_MESSAGES="zh_CN.GBK": 控制系统消息的本地化,例如错误消息和提示。
LC_PAPER="zh_CN.GBK": 控制默认纸张的尺寸。
LC_NAME="zh_CN.GBK": 控制名字格式,例如姓名的顺序和称呼。
LC_ADDRESS="zh_CN.GBK": 控制地址格式,例如街道、城市和邮政编码的顺序。
LC_TELEPHONE="zh_CN.GBK": 控制电话号码格式。
LC_MEASUREMENT="zh_CN.GBK": 控制度量单位,例如使用公制还是英制。
LC_IDENTIFICATION="zh_CN.GBK": 控制元数据,例如语言、地区和字符集。
LC_ALL=zh_CN.GBK: 这个变量用于覆盖所有其他LC_变量和LANG变量。在这里,它设置了所有本地化类别为中国简体中文和GBK字符集。

1.2 终端字符集

图片
图片

我们一般使用终端软件远程登陆服务器,在登陆的时候需要选择编码即字符集,实际上这个字符集就是设置远程服务器操作系统的环境变量LC_ALL。

1.3 MySQL字符集

MySQL的字符集设置提供了灵活的层次结构,这些层次分4层,允许你在服务器、数据库、表和列级别控制字符集和排序规则,这有助于确保数据的一致性和正确性,特别是在处理多语言和国际化环境时。

以下是各个层次的参数:

1. 服务器层次 服务器层次的字符集设置适用于MySQL服务器实例的全局设置。

- `character_set_server`: 服务器的默认字符集。 - `collation_server`: 服务器的默认排序规则。

2. 数据库层次 你可以为特定数据库设置字符集和排序规则,这将覆盖服务器层次的设置。

- `CREATE DATABASE db_name CHARACTER SET charset_name COLLATE collation_name;`: 创建数据库时指定字符集和排序规则。 - `ALTER DATABASE db_name CHARACTER SET charset_name COLLATE collation_name;`: 修改现有数据库的字符集和排序规则。

3. 表层次 你可以为特定表设置字符集和排序规则,这将覆盖数据库和服务器层次的设置。

- `CREATE TABLE tbl_name (...) CHARACTER SET charset_name COLLATE collation_name;`: 创建表时指定字符集和排序规则。 - `ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name COLLATE collation_name;`: 修改现有表的字符集和排序规则。

4. 列层次 你可以为表中的特定列设置字符集和排序规则,这将覆盖表、数据库和服务器层次的设置。

- 在`CREATE TABLE`或`ALTER TABLE`语句中,为特定列指定`CHARACTER SET charset_name`和`COLLATE collation_name`。

1.4 客户端字符集

客户端连接到MySQL服务器时也可以设置字符集。

- `character_set_client`: 控制客户端字符集。 - `character_set_connection`: 控制连接层字符集。 - `character_set_results`: 控制查询结果字符集。

这3个字符集的具体功能见下图:

图片
图片

MySQL命令:set names latin1 相当于设置session级别的character_set_client, character_set_connection, 和character_set_results 为latin1字符集。

1.5 简单示例

我们用python来显示下"数据库"在不同字符集下的16进制编码:

代码语言:javascript
复制
text = "数据库"
gbk_encoded = text.encode('GBK')
gbk_hex = gbk_encoded.hex()
print("GBK:"+gbk_hex)  

utf8_encoded = text.encode('UTF8')
utf8_hex = utf8_encoded.hex()
print("UTF8:"+utf8_hex)  

 运行结果如下:

代码语言:javascript
复制
GBK:cafdbeddbfe2
UTF8:e695b0e68daee5ba93

 可以看到因为GBK的汉字是双字节,所以一共6个字节。UTF8汉字是3字节,所以一共是9字节。

我们进行一个简单的测试,从1个网页上复制汉字"数据库"到linux的文本文件中,这个网页的原始编码是什么呢?查看网页源文件,可以看出是UTF8编码:

代码语言:javascript
复制
<head lang="zh-CN"><meta charset="UTF-8">

然后用vim将汉字粘贴到文本文件utf8中,查看文本内容和16进制编码: 

代码语言:javascript
复制
[root@VM-94-230-centos /data/test/char]# cat utf8.txt 
数据库
[root@VM-94-230-centos /data/test/char]# hexdump utf8.txt 
0000000 95e6 e6b0 ae8d bae5 0a93               
000000a

在MySQL里查询编码:

GBK: select hex('数据库'); CAFDBEDDBFE2

UTF8: select hex('数据库'); E695B0E68DAEE5BA93

2.  字符集转换

2.1 通过内码转换

GBK到UTF8的转换涉及解码原始字节序列到内码(Unicode),然后重新编码为目标字符集。这个过程依赖于源和目标字符集的精确定义,以及用于执行转换的工具和库:

1. 解码(Decoding): 首先,需要将GBK编码的字节序列解码为内码。在这个过程中,每个GBK编码的字节序列被映射到相应的Unicode字符。

说明:内码(Internal Code)是指计算机系统内部使用的字符编码。在处理文本数据时,计算机系统通常会将外部编码(例如用户输入或文件中的编码)转换为内部统一的编码格式。这样做的目的是简化字符处理和操作,因为内码通常是为了适应特定系统或应用程序的需求而设计的。

以下是一些关于内码的关键点:

1)统一处理: 通过使用内码,系统可以将来自不同源和不同编码的文本统一为一种格式,从而简化文本处理和操作。

2)与平台无关: 内码通常设计为与特定平台或硬件无关,这样可以确保在不同系统之间传输和处理文本时的一致性。

3)转换: 当文本从外部源(例如文件、网络或用户输入)进入系统时,它通常会被转换为内码。同样,当文本离开系统时,它通常会被转换回适当的外部编码。

4)例子:Unicode是一种常用的内码标准,它旨在包括世界上所有的书写系统。许多现代操作系统和编程语言都使用Unicode作为内码,因为它允许用统一的方式处理各种不同的字符集。

5)与字符集和编码的关系: 字符集是一组字符的集合,而编码是字符集的具体表示。内码是一种特殊类型的编码,用于系统内部的字符表示。

总的来说,内码是计算机系统内部使用的字符编码,用于统一和简化文本处理。通过将外部编码转换为内码,系统可以更容易地处理来自不同源和不同编码的文本。

2. 编码(Encoding): 接下来,将Unicode字符编码为UTF-8字节序列。UTF-8是一种可变长度的字符编码,它使用1到4个字节来表示每个Unicode字符。UTF-8的设计允许对ASCII字符的向后兼容,这意味着任何有效的ASCII字符串也是有效的UTF-8字符串。

转换工具: 许多编程语言和操作系统提供了用于字符集转换的库和工具。例如,在Python中,你可以使用`encode`和`decode`方法轻松地在不同的字符集之间转换。这些工具通常基于预定义的字符映射表,这些表定义了如何在不同的字符集之间转换字符。

示例代码:

以下是一个使用Python将GBK编码的字符串转换为UTF-8编码的示例:

代码语言:javascript
复制
original_text_gbk = b'\xc4\xe3\xba\xc3' # GBK编码的"你好"
decoded_text = original_text_gbk.decode('GBK') # 解码为Unicode
encoded_text_utf8 = decoded_text.encode('UTF-8') # 编码为UTF-8

print(decoded_text)
print(encoded_text_utf8)

运行结果:

代码语言:javascript
复制
你好
b'\xe4\xbd\xa0\xe5\xa5\xbd'

这里unicode是字符的全集,然后GBK、UTF8字符集与unicode之间有一一对应的映射表,通过查询2张映射表就能成功的进行字符集转换。这一种转换一般是无损的,即不会丢失原始信息。

那么通过unicode可以实现任意2个字符集之间的转换吗?实际是不一定,比如:

gbk->unicode->latin1  不可以 utf8->unicode->latin1  不可以

上面2种转换不可以是因为latin1字符集只能表示256个字符,绝大部分GBK和UTF8的字符在latin1字符集里面根本没有对应编码。 下面再看一些例子: python例子:

>>> '数据库'.decode('UTF-8') u'\u6570\u636e\u5e93'

>>> '数据库'.decode('GBK') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'gbk' codec can't decode byte 0x93 in position 8: incomplete multibyte sequence

这里转换失败是因为字符串实际是UTF8编码,但要求python用GBK换为unicode编码,但GBK和unicode的映射表里面没有找到对应的编码。

>>> 'hello'.decode('UTF-8') u'hello'

>>> '&'.decode('UTF-8') u'&'

>>> '数据库'.decode('UTF-8').encode('latin1') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'latin-1' codec can't encode characters in position 0-2: ordinal not in range(256)

这里转换失败是因为UTF8字符没有找到latin1字符集中对应的编码。

>>> u'\u6570'.encode('latin1') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'latin-1' codec can't encode character u'\u6570' in position 0: ordinal not in range(256)

>>> '数据库'.decode('UTF-8').encode('GBK') '\xca\xfd\xbe\xdd\xbf\xe2'

>>> '数据库'.decode('UTF-8').encode('UTF-8') '\xe6\x95\xb0\xe6\x8d\xae\xe5\xba\x93'

>>> '数据库'.decode('UTF-8').encode('GBK').decode('latin1') u'\xca\xfd\xbe\xdd\xbf\xe2'

2.2 直接转换

如果我们不通过unicode,直接转换可以吗?

这里有2个问题:

1. 转换后对应的字符会发生变化,不再是原来的字符了

2. GBK汉字是双字节,UTF8汉字是3字节,转换过程中可以生产单个字节剩余

3. 因为GBK并不是0000-FFFF的全集,UTF8也不是000000-FFFFFF的合集,所以有些转换会找不到对应的字符

问题2,3导致转换是有损的,即会丢失原始信息,无法复原。

下面看一些例子,第一个看UTF8转GBK:

代码语言:javascript
复制
text = "数据库"
utf8_encoded = text.encode('UTF8')

print(utf8_encoded)

encoded_text_gbk = utf8_encoded.decode('GBK') # 编码为UTF-8

print(encoded_text_gbk)

 运行报错:

代码语言:javascript
复制
b'\xe6\x95\xb0\xe6\x8d\xae\xe5\xba\x93'
---------------------------------------------------------------------------
UnicodeDecodeError                        Traceback (most recent call last)
Cell In[38], line 6
      2 utf8_encoded = text.encode('UTF8')
      4 print(utf8_encoded)
----> 6 encoded_text_gbk = utf8_encoded.decode('GBK') # 编码为UTF-8
      8 print(encoded_text_gbk)

UnicodeDecodeError: 'gbk' codec can't decode byte 0x93 in position 8: incomplete multibyte sequence

这是因为"数据库"这3个汉字的GBK编码是9个字节,换为双字节的GBK的时候,尾部有一个单字节的字符无法转换。

那我如果取前8个字节呢?

代码语言:javascript
复制
text = "数据库"
utf8_encoded = text.encode('UTF8')
utf8_encoded = b'\xe6\x95\xb0\xe6\x8d\xae\xe5\xba'

print(utf8_encoded)

encoded_text_gbk = utf8_encoded.decode('GBK') # 编码为UTF-8

print(encoded_text_gbk)

 运行结果:

代码语言:javascript
复制
b'\xe6\x95\xb0\xe6\x8d\xae\xe5\xba'
鏁版嵁搴

 顺利转换为了4个不同的汉字!这是一种乱码的原因。

实际上,可以用参数errors='replace'忽略部分字节的转换错误:

代码语言:javascript
复制
text = "数据库"
utf8_encoded = text.encode('UTF8')

print(utf8_encoded)

encoded_text_gbk = utf8_encoded.decode('GBK',errors='replace') # 编码为UTF-8

print(encoded_text_gbk)
print(encoded_text_gbk.encode('UTF8'))

 运行结果:

代码语言:javascript
复制
b'\xe6\x95\xb0\xe6\x8d\xae\xe5\xba\x93'
鏁版嵁搴�
b'\xe9\x8f\x81\xe7\x89\x88\xe5\xb5\x81\xe6\x90\xb4\xef\xbf\xbd'

注意字节序列\xef\xbf\xbd表示UTF-8编码的替换字符(Replacement Character),其Unicode代码点为U+FFFD。替换字符通常用于替换输入中无法表示的字符。例如,当你尝试将一个无效的字节序列解码为字符串时,解码器可能无法确定该序列应该表示什么字符。在这种情况下,解码器可以插入替换字符来表示原始序列中的错误或未知部分。在许多系统和应用程序中,替换字符通常显示为一个黑色的菱形,其中包含一个白色的问号(�)。此时原始信息已经有部分丢失了!

再看一个例子,GBK转UTF8,这种转换其实 99%不可以,只有少数可以,如"平遥"

代码语言:javascript
复制
text = "平遥"
gbk_encoded = text.encode('GBK')

print(gbk_encoded)

encoded_text_utf8 = gbk_encoded.decode('UTF8',errors='replace') # 编码为UTF-8

print(encoded_text_utf8)

 运行结果:

代码语言:javascript
复制
b'\xc6\xbd\xd2\xa3'
ƽң

11000110 10111101 11010010 10100011 可以转换因为"平遥"符合utf8 2字节符号编码规则110… 10…,如果把这个汉字用GBK编码保存到记事本,智能识别有可能出错,显示不是“平遥”。 可能引起误断的汉字见: http://blog.csdn.net/yimengqiannian/article/details/7060565

gbk->latin1  可以,变为单字节字符,因为latin1字符集包括了00-FF的所有区间,所以转换过程中一定不会丢失信息,可以视为万能字符集。这也是为什么MySQL可以用latin1字符集存GBK或者UTF8汉字的原因。 utf8->latin1  可以,变为单字节字符

代码语言:javascript
复制
text = "平遥"
gbk_encoded = text.encode('GBK')

print(gbk_encoded)

encoded_text_lain1 = gbk_encoded.decode('Latin1',errors='replace') # 编码为UTF-8

print(encoded_text_lain1)
print(encoded_text_lain1.encode('Latin1'))

运行结果:

代码语言:javascript
复制
b'\xc6\xbd\xd2\xa3'
ƽң
b'\xc6\xbd\xd2\xa3'

3. 摸拟测试

gbk->gbk->gbk 按顺序分别表示插入字符串原始字符集,客户端字符集,表字符集,简单理解就是字符的原始字符集,我们告诉数据库字符是什么字符集,目标字符集。我们告诉数据库字符是什么字符集可以用"set names XXX"命令。

考虑gbk, utf8, latin1三种主流字符集,则一共有27种组合, 下面一一列举:

3.1 完全匹配

gbk->gbk->gbk utf8->utf8->utf8

这一种是最理想的,一定不会有乱码。

3.2 插入时进行正确的unicode转换

gbk->gbk->utf8 select hex(convert(CONVERT(UNHEX( ‘CAFDBEDDBFE2′) USING gbk) using utf8)); E695B0E68DAEE5BA93

utf8->utf8->gbk select hex(convert(CONVERT(UNHEX( ‘E695B0E68DAEE5BA93′) USING utf8) using gbk)); CAFDBEDDBFE2

这一种相当于原始字符集与我告诉数据库的字符集匹配,数据库会利用内码unicode进行转换,也不会有乱码。

3.3 latin1单字节流保存

gbk->latin1->latin1 select hex(convert(CONVERT(UNHEX( ‘CAFDBEDDBFE2′) USING latin1) using latin1)); CAFDBEDDBFE2

utf8->latin1->latin1 select hex(convert(CONVERT(UNHEX( ‘E695B0E68DAEE5BA93′) USING latin1) using latin1)); E695B0E68DAEE5BA93

这一种就是利用了latin1是万能字符集,覆盖了00-FF的所有区间,将UTF8和GBK视为单字节字节流,用Latin1存储不会有乱码。但在读取的时候还是要 set names 实际的编码。

3.4 转为unicode后再转为latin1 无法表示,转为3F (latin1 中的?号)

gbk->gbk->latin1 select hex(convert(CONVERT(UNHEX( ‘CAFDBEDDBFE2′) USING gbk) using latin1)); 3F3F3F

utf8->utf8->latin1 select hex(convert(CONVERT(UNHEX( ‘E695B0E68DAEE5BA93′) USING utf8) using latin1)); 3F3F3F

utf8->gbk->latin1 select hex(convert(CONVERT(UNHEX( ‘E695B0E68DAEE5BA93′) USING gbk) using latin1)); 3F3F3F3F

上面的转换实际都失败了,因为latin1字符集只有256个字符,绝大多数的GBK和UTF8字符都无法用Latin1字符集表示。在Latin-1(ISO 8859-1)字符集中,十六进制值3F对应于问号字符(?)。这个字符经常用于替换无法识别或无法表示的字符。例如,当你尝试使用Latin-1编码一个不在Latin-1范围内的字符时,你可以选择使用问号?来替换那个字符,这就是为什么在许多编码转换错误中你会看到问号的原因。

3.5 不符合utf8规则,无法转换,保存为空

gbk->utf8->latin1 gbk->utf8->utf8 gbk->utf8->gbk select hex(convert(CONVERT(UNHEX( ‘CAFDBEDDBFE2′) USING utf8) using latin1)); Warning | 1300 | Invalid utf8 character string: ‘CAFDBE’

字符实际是GBK编码,我们告诉数据库是UTF8编码,然而数据库尝试用UTF8编码大部分会失败。

3.6 utf8 转换为双字节汉字后,尾部奇数字节截断

utf8->gbk->gbk select hex(convert(CONVERT(UNHEX( ‘E695B0E68DAEE5BA93′) USING gbk) using gbk)); E695B0E68DAEE5BA | Warning | 1300 | Invalid gbk character string: ‘93′ |

utf8->gbk->utf8 select hex(convert(CONVERT(UNHEX( ‘E695B0E68DAEE5BA93′) USING gbk) using utf8)); E98F81E78988E5B581E690B4 | Warning | 1300 | Invalid gbk character string: ‘93′ |

3.7 latin1 7f后的字符无法全部转为gbk

gbk->latin1->gbk select hex(convert(CONVERT(UNHEX( ‘CAFDBEDDBFE2′) USING latin1) using gbk)); 3F3F3F3F3F3F

utf8->latin1->gbk 注意 B0转为A1E3 93转为A1B0 select hex(convert(CONVERT(UNHEX( ‘E695B0E68DAEE5BA93′) USING latin1) using gbk)); 3F3FA1E33F3F3F3F3FA1B0

select hex(convert(CONVERT(UNHEX('5F6A7F80') USING latin1) using gbk)); 5F6A7F3F

这是因为MySQL的Latin1字符集7F之前是ASC II码,在GBK和UTF8字符集中也是一样的编码,但7F之后的字符,可能无法通过unicdoe转为GBK编码!

3.8 latin1字符转为utf8,7f后的字符变为2字节或者3字节

gbk->latin1->utf8 12字节 select hex(convert(CONVERT(UNHEX( ‘CAFDBEDDBFE2′) USING latin1) using utf8)); C38AC3BDC2BEC39DC2BFC3A2

utf8->latin1->utf8  20字节, latin1 的 95,93转为utf8的3字节,所以是3*6+2=20字节 select hex(convert(CONVERT(UNHEX( ‘E695B0E68DAEE5BA93′) USING latin1) using utf8)); C3A6E280A2C2B0C3A6C28DC2AEC3A5C2BAE2809C

4. 脚本测试

4.1 测试脚本

#!/usr/bin/sh

sql=” create table if not exists chartest.t_utf8 (chartable varchar(100), charclient varchar(100), chardata varchar(100), data varchar(100), msg varchar(500), primary key (chartable,charclient,chardata) )default charset=utf8;

create table if not exists chartest.t_gbk (chartable varchar(100), charclient varchar(100), chardata varchar(100), data varchar(100), msg varchar(500), primary key (chartable,charclient,chardata) )default charset=gbk;

create table if not exists chartest.t_latin1 (chartable varchar(100), charclient varchar(100), chardata varchar(100), data varchar(100), msg varchar(500), primary key (chartable,charclient,chardata) )default charset=latin1;

truncate table chartest.t_utf8; truncate table chartest.t_gbk; truncate table chartest.t_latin1; ”

mysql -e”$sql”

utf8=$(cat utf8.txt) gbk=$(cat gb2312.txt)

charset=(latin1 utf8 gbk)

for((i=0;i<${#charset[*]};i++)) do charclient=${charset[$i]} for((j=0;j<${#charset[*]};j++)) do chartable=${charset[$j]} echo “client=$charclient table=$chartable data=utf8″ sql=”use chartest;set names $charclient;insert into t_$chartable values(‘$chartable’,'$charclient’,'utf8′,’$utf8′,”);” msg=$(mysql –show-warnings=true -e”$sql”) sql=”use chartest;update t_$chartable set msg=”$msg” where chartable=’$chartable’ and charclient=’$charclient’ and chardata=’utf8′;” mysql –show-warnings=true -e”$sql”

echo “client=$charclient table=$chartable data=gbk” sql=”use chartest;set names $charclient;insert into t_$chartable values(‘$chartable’,'$charclient’,'gbk’,'$gbk’,”);” #echo “$sql” msg=$(mysql –show-warnings=true -e”$sql”) sql=”use chartest;update t_$chartable set msg=”$msg” where chartable=’$chartable’ and charclient=’$charclient’ and chardata=’gbk’;” mysql –show-warnings=true -e”$sql” done done

4.2 测试结果

举一个例子:

表字符集GBK

代码语言:javascript
复制
CREATE TABLE `ts` (
  `fname` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=gbk

连接字符集utf8mb4

代码语言:javascript
复制
mysql> show variables like 'char%';
+--------------------------+------------------------------------+
| Variable_name            | Value                              |
+--------------------------+------------------------------------+
| character_set_client     | utf8mb4                            |
| character_set_connection | utf8mb4                            |
| character_set_database   | utf8mb4                            |
| character_set_filesystem | binary                             |
| character_set_results    | utf8mb4                            |
| character_set_server     | utf8mb4                            |
| character_set_system     | utf8mb3                            |
| character_sets_dir       | /data/mysql/mysql8/share/charsets/ |
+--------------------------+------------------------------------+
8 rows in set (0.00 sec)

 插入数据字符集UTF8

代码语言:javascript
复制
mysql> insert into ts values('数据库');
Query OK, 1 row affected (0.00 sec)

 查询16进制编码:

代码语言:javascript
复制
mysql> select hex(fname)  from test01.ts;
+--------------+
| hex(fname)   |
+--------------+
| CAFDBEDDBFE2 |
+--------------+
1 row in set (0.00 sec)

 是用GBK的双字节存储。

查询数据:

代码语言:javascript
复制
mysql> select *  from test01.ts;
+-----------+
| fname     |
+-----------+
| 数据库    |
+-----------+
1 row in set (0.00 sec)

 为什么能正常显示?因为虽然数据的字符集是GBK,但连接字符集是UTF8,所以数据库进行了转换,然后终端(操作系统)字符集也是UTF8,所以能正常显示。

代码语言:javascript
复制
mysql> set names gbk;
Query OK, 0 rows affected (0.00 sec)

mysql> select *  from test01.ts;
+--------+
| fname  |
+--------+
| ���ݿ�      |
+--------+
1 row in set (0.00 sec)

set names gbk后,显示出现乱码,这是因为终端(操作系统)字符集是UTF8,显示的时候做了转换,但GBK直接换为UTF8,绝大部分字符都无法转换,显示为"�"号。此时我们将终端字符集设置为GBK,即可正常显示。

具体测试结果见下图:

终端字符集:gbk set names latin1;

图片
图片

set names gbk;

图片
图片

set names utf8;

图片
图片

下一篇《MySQL字符集终级指南--实战篇》将用一些实战例子来说明字符集设置不当可能遇到的种种问题,敬请期待。


公众号精华文章:

1.MySQL谬误集01:读不加锁 2.MySQL8.1来了:MySQL创新和长期支持(LTS)版本简介 3.Gh-ost改表P0级BUG:可能导致数据丢失 4.从一道数据库面试题彻谈MySQL加锁机制 5.MySQL字符编码指南--基础篇 6.从财政学专业到TOP金融数据库DBA--我的学习之路 7.大胆假设小心求证:MySQL双写+双向复制实战

微信公众号"数据库之巅"分享这十几年来我在数据库特别是互联网金融数据库运维走过的路和踩过的坑,欢迎大家关注。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 字符集四类设置
    • 1.1 操作系统字符集
      • 1.2 终端字符集
        • 1.3 MySQL字符集
          • 1.4 客户端字符集
            • 1.5 简单示例
            • 2.  字符集转换
              • 2.1 通过内码转换
                • 2.2 直接转换
                • 3. 摸拟测试
                  • 3.1 完全匹配
                    • 3.2 插入时进行正确的unicode转换
                      • 3.3 latin1单字节流保存
                        • 3.4 转为unicode后再转为latin1 无法表示,转为3F (latin1 中的?号)
                          • 3.5 不符合utf8规则,无法转换,保存为空
                            • 3.6 utf8 转换为双字节汉字后,尾部奇数字节截断
                              • 3.7 latin1 7f后的字符无法全部转为gbk
                                • 3.8 latin1字符转为utf8,7f后的字符变为2字节或者3字节
                                • 4. 脚本测试
                                  • 4.1 测试脚本
                                    • 4.2 测试结果
                                    相关产品与服务
                                    云数据库 MySQL
                                    腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
                                    领券
                                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档