MySQL 乱码之我见

标签: mysql db | 发表时间:2015-06-19 16:14 | 作者:netingcn
出处:http://segmentfault.com/blogs

先着重介绍一下mysql的字符集,这样能对产生mysql的根源有一个了解。
mysql 的字符集支持有两个方面:字符集(Character set)和排序方式(Collation)。另外对于字符集的支持细化到四个层次: 服务器(server),数据库(database),数据表(table)和连接(connection)。

连上mysql 后使用status 命令,可以看到类似如下输出:

  >mysql status
Connection id:          305
Current database:
Current user:           root@localhost
SSL:                    Not in use
Current pager:          stdout
Using outfile:          ''
Using delimiter:        ;
Server version:         5.6.23 MySQL Community Server (GPL)
Protocol version:       10
Connection:             Localhost via UNIX socket
Server characterset:    utf8
Db     characterset:    utf8
Client characterset:    utf8
Conn.  characterset:    utf8

Server characterset 就是mysql默认字符集,当创建数据库没有指定字符集时数据库就采用此默认值。可以在mysql的配置文件中的 mysqld 段中对此值进行修改

  [mysqld]
port        = 3306
socket      = /tmp/mysql.sock
character-set-server = utf8
collation-server = utf8_general_ci 

Db characterset:是当前数据库默认的字符集,当创建表时没有指定字符集,此表就使用当前默认值。例如创建一个 db_test 数据库,字符集使用 latin1

  CREATE DATABASE `db_test` CHARACTER SET 'latin1' COLLATE 'latin1_swedish_ci';

use db_test;

然后再使用 status 命令,可以看到这个时候 Db characterset 变为 latin1 了

  >mysql status
Connection id:          305
Current database:       db_test
Current user:           root@localhost
SSL:                    Not in use
Current pager:          stdout
Using outfile:          ''
Using delimiter:        ;
Server version:         5.6.23 MySQL Community Server (GPL)
Protocol version:       10
Connection:             Localhost via UNIX socket
Server characterset:    utf8
Db     characterset:    latin1
Client characterset:    utf8
Conn.  characterset:    utf8

在数据库中分别创建两种表 test1 和 test2,其中 test1 使用默认字符集, test2 指定字符集为GBK

  create table test1 (name varchar(20));

create table test2 (name varchar(20)) default charset=GBK;

使用 show create table 命令查看上述两张表,可以看到 test1 使用了当前数据库的默认字符集latin1,而test2使用的字符集是GBK。

  mysql> show create table test1;
+-------+-------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                    |
+-------+-------------------------------------------------------------------------------------------------+
| test1 | CREATE TABLE `test1` (
  `name` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+-------------------------------------------------------------------------------------------------+

mysql> show create table test2;
+-------+----------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                 |
+-------+----------------------------------------------------------------------------------------------+
| test2 | CREATE TABLE `test2` (
  `name` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=gbk |
+-------+----------------------------------------------------------------------------------------------+

mysql 存储信息最终是已二进制的形式来存储的。所以在存储之前就需要对信息进行编码,同时从数据库读取信息后需要解码。具体使用那种编码、解码方式就是根据Client characterset以及表对应的字符集,如果没有显示的指定,那么会有一个默认值。当使用命令行的方式连接mysql,可以在mysql 配置中 mysql 段来指定默认Client characterset。例如:

  [client]
port        = 3306
socket      = /tmp/mysql.sock
default-character-set   = utf8

也可以使用在连接时候指定

  mysql -uroot -p --default-character-set=utf8 

另外在登录mysql 后也可以使用 set names 来指定

  set names utf8

关于优先级,set names utf8 最高,mysql -uroot -p --default-character-set=utf8 其次、my.cnf 最后。

上面对字符集做了一个简单的介绍,建议大家也把上面的mysql 命令试一下,这样理解或更加深刻。现在再来说一下乱码的情况,一般出现乱码就是因为字符集(编码)不同,换句话说就是当字符集(编码)一致时就不会出现乱码。前面介绍了一下字符集,所以知道了好几种,那到底是需要什么字符集一致呢?答案是:Client characterset 与 数据库表的字符集。 下面还是通过例子来说明,使用上面创建的表 test1。

由于test1使用的字符集是 latin1,那么使用下面的方式连上mysql

  mysql -uroot -p  db_test --default-character-set=latin1

再次确认一下Client characterset 与 数据库表的字符集

  mysql> status
--------------
mysql  Ver 14.14 Distrib 5.6.23, for osx10.8 (x86_64) using  EditLine wrapper

Connection id:          310
Current database:       db_test
Current user:           root@localhost
SSL:                    Not in use
Current pager:          stdout
Using outfile:          ''
Using delimiter:        ;
Server version:         5.6.23 MySQL Community Server (GPL)
Protocol version:       10
Connection:             Localhost via UNIX socket
Server characterset:    utf8
Db     characterset:    latin1
Client characterset:    latin1
Conn.  characterset:    latin1

-------------------------

mysql> show create table test1;
+-------+-------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                    |
+-------+-------------------------------------------------------------------------------------------------+
| test1 | CREATE TABLE `test1` (
  `name` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+-------------------------------------------------------------------------------------------------+

可以看到Client characterset与表的字符集是一致的,然后插入一条含有中文的记录,同时查询看看。

  mysql> insert into test1(name) values('中test文1234测试');

mysql> select * from test1;
+----------------------+
| name                 |
+----------------------+
| 中test文1234测试 |
+----------------------+

现在证明当Client characterset与表的字符集一致时,没有出现乱码。那现在使用set names 来修改一下 Client characterset 看看效果。

  mysql> set names utf8;
Query OK, 0 rows affected (0.00 sec)

mysql> status
--------------
mysql  Ver 14.14 Distrib 5.6.23, for osx10.8 (x86_64) using  EditLine wrapper

Connection id:          310
Current database:       db_test
Current user:           root@localhost
SSL:                    Not in use
Current pager:          stdout
Using outfile:          ''
Using delimiter:        ;
Server version:         5.6.23 MySQL Community Server (GPL)
Protocol version:       10
Connection:             Localhost via UNIX socket
Server characterset:    utf8
Db     characterset:    latin1
Client characterset:    utf8
Conn.  characterset:    utf8

mysql> select * from test1;
+--------------------------------------+
| name                                 |
+--------------------------------------+
| 中test文1234测试 |
+--------------------------------------+

utf8 出现乱码,再试试gbk

  mysql> set names gbk;
Query OK, 0 rows affected (0.00 sec)

mysql> status
--------------
mysql  Ver 14.14 Distrib 5.6.23, for osx10.8 (x86_64) using  EditLine wrapper

Connection id:          310
Current database:       db_test
Current user:           root@localhost
SSL:                    Not in use
Current pager:          stdout
Using outfile:          ''
Using delimiter:        ;
Server version:         5.6.23 MySQL Community Server (GPL)
Protocol version:       10
Connection:             Localhost via UNIX socket
Server characterset:    utf8
Db     characterset:    latin1
Client characterset:    gbk
Conn.  characterset:    gbk

mysql> select * from test1;
+------------------------+
| name                   |
+------------------------+
| ???test?1234???? |
+------------------------+

上面把Client characterset 设置分别设置为 utf8 或 GBK 后,然后查询都出现了乱码,而且乱码显示还不一样。下面再测试一样不同Client characterset字符集先插入在读取的情况。

  mysql -uroot -p  db_test --default-character-set=utf8

 mysql> status
--------------
mysql  Ver 14.14 Distrib 5.6.23, for osx10.8 (x86_64) using  EditLine wrapper

Connection id:          312
Current database:       db_test
Current user:           root@localhost
SSL:                    Not in use
Current pager:          stdout
Using outfile:          ''
Using delimiter:        ;
Server version:         5.6.23 MySQL Community Server (GPL)
Protocol version:       10
Connection:             Localhost via UNIX socket
Server characterset:    utf8
Db     characterset:    latin1
Client characterset:    utf8
Conn.  characterset:    utf8

mysql> truncate table test1;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from test1;
Empty set (0.00 sec)

mysql> insert into test1(name) values('中test文1234测试');                                                                                                                                             
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> select * from test1;
+--------------+
| name         |
+--------------+
| ?test?1234?? |
+--------------+

上面的例子说明当字符集不一致出现乱码了。 如果再把Client characterset 修改为和数据库表一致,然后看看刚刚插入的记录是否还是显示乱码

  mysql> set names latin1;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+--------------+
| name         |
+--------------+
| ?test?1234?? |
+--------------+
1 row in set (0.00 sec)

还是乱码,也就是通过字符集设置也无法把乱码还原了。

通过上面这些例子可以得出结论,只有 当Client characterset与表的字符集一致才不会出现乱码

相关 [mysql 乱码 我见] 推荐:

MySQL 乱码之我见

- - SegmentFault 最新的文章
先着重介绍一下mysql的字符集,这样能对产生mysql的根源有一个了解. mysql 的字符集支持有两个方面:字符集(Character set)和排序方式(Collation). 另外对于字符集的支持细化到四个层次: 服务器(server),数据库(database),数据表(table)和连接(connection).

Mysql 乱码问题--如何查看和修改Mysql 的字符集

- - ITeye博客
MySQL会出现中文乱码的原因不外乎下列几点:.    1.server本身设定问题,例如还停留在latin1.    2.table的语系设定问题(包含character与collation).    3.客户端程式(例如 php)的连线语系设定问题.    utf8可以兼容世界上所有字符!!!!.

老叶观点:MySQL开发规范之我见

- - iMySQL
大多数MySQL规范在网上也都能找得到相关的分享,在这里要分享的是老叶个人认为比较重要的,或者容易被忽视的,以及容易被混淆的一些地方. 1、默认使用InnoDB引擎. 【老叶观点】已多次呼吁过了,InnoDB适用于几乎99%的MySQL应用场景,而且在MySQL 5.7的系统表都改成InnoDB了,还有什么理由再死守MyISAM呢.

(原创)Linux下MySQL 5.5的修改字符集编码为UTF8(彻底解决中文乱码问题)

- - 服务器运维与网站架构|Linux运维|X研究
PS:昨天一同事遇到mysql 5.5中文乱码问题,找我解决. 解决了,有个细节问题网上没人说,我就总结一下. 一、登录MySQL查看用SHOW VARIABLES LIKE ‘character%’;下字符集,显示如下:. character_set_database和character_set_server的默认字符集还是latin1.

mysql保存中文乱码的原因和解决办法(首发经典实用版)

- - CSDN博客推荐文章
    当你遇到这个mysql保存中文乱码问题的时候,期待找到mysql保存中文乱码的原因和解决办法(首发经典实用版)这样一篇能解决问题的文章是多么激动人心.     也许30%的程序员会选择自己百度,结果发现网友已经贴了很多类似“mysql 中文乱码”、“php mysql 中文乱码”、“mysql5.5中文乱码”、“mysql 乱码”、“mysql乱码问题”、“mysql jsp 乱码”、“mysql jdbc 乱码”、“mysql 查询乱码”、“mysql 导入数据乱码”等一系列问题,到底哪个是自己要找的能解决自己问题的呀.

Linux Ksplice,MySQL and Oracle

- Syn - DBA Notes
Oracle 在 7 月份收购了 Ksplice. 使用了 Ksplice 的 Linux 系统,为 Kernel 打补丁无需重启动,做系统维护的朋友应该明白这是一个杀手级特性. 现在该产品已经合并到 Oracle Linux 中. 目前已经有超过 700 家客户,超过 10 万套系统使用了 Ksplice (不知道国内是否已经有用户了.

MySQL Replication 线程

- - CSDN博客推荐文章
Replication 线程. Mysql 的Replication 是一个异步的复制过程,从一个Mysql instace(我们称之为Master)复制到另一个Mysql instance(我们称之Slave). 在Master 与Slave 之间的实现整个复制过程主. 要由三个线程来完成,其中两个线程(Sql 线程和IO 线程)在Slave 端,另外一个线程(IO 线程)在Master 端.

mysql backup 脚本

- - ITeye博客
网上备份脚本很多,但考虑都不周全. 保证创建备份文件只能是创建者跟root可以访问,其他用户没有权限,保证了数据库备份的安全. 上面脚本是负责备份的份数管理,. 已有 0 人发表留言,猛击->> 这里<<-参与讨论. —软件人才免语言低担保 赴美带薪读研.

Oracle MySQL Or NoSQL续

- - Sky.Jian 朝阳的天空
接前面一篇,这里再将之前在“中国系统架构师大会”5周年的时候发布的纪念册“IT架构实录”上的一篇文章发出来,也算是前面博文中PPT的一个文字版解读吧. Oracle,MySQL 还是 NoSQL. 随着阿里系的“去IOE”运动在社区的宣传声越来越大,国内正在掀起一股“去xxx”的技术潮. 不仅仅是互联网企业,包括运营商以及金融机构都已经开始加入到这个潮流之中.

mysql优化

- - 数据库 - ITeye博客
公司网站访问量越来越大,MySQL自然成为瓶颈,因此最近我一直在研究 MySQL  的优化,第一步自然想到的是 MySQL 系统参数的优化,作为一个访问量很大的网站(日20万人次以上)的数据库系统,不可能指望 MySQL  默认的系统参数能够让 MySQL运行得非常顺畅. 在Apache, PHP,  MySQL的体系架构中,MySQL对于性能的影响最大,也是关键的核心部分.