前言

在更新数据库时,有时会遇到这样的错误:

Illegal mix of collations (gbk_chinese_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '='

这是什么原因呢,先来讲一下字符集的相关知识吧。

深入分析问题

1、MySQL5的字符集支持

MySQL5.1 中的字符集支持包括在MyISAM、MEMORY和InnoDB存储引擎中。MySQL5支持多种字符集来存储字符串,对每种字符集也有相应的校对规则 (Collation)来进行比较。MySQL5还支持从服务器、数据库到数据库表、列、连接等多种级别的字符集校对规则

2、MySQL5字符集及校对规则

MySQL5字符集和校对规则有4个级别的默认设置:服务器级、数据库级、表级和连接级。

1)服务器字符集和校对

MySQL服务器有一个服务器字符集和一个服务器校对规则,它们均不能设置为空。

MySQL按照如下方法确定服务器字符集和服务器校对规则:

·当服务器启动时根据有效的选项设置

·根据运行时的设定值

可以通过在构建安装程序时将--with-charset和--with-collation作为configure的参数来设定服务器字符集和校对。

如  shell> ./configure --with-charset=latin1 --with-collation=latin1_german1_ci

运行时服务器字符集和校对规则是character_set_server和collation_server这两个系统变量表示的,可以通过修改它们来相应的改变。

2)数据库字符集和校对

每一个数据库有一个数据库字符集和一个数据库校对规则,它不能够为空。MySQL这样选择数据库字符集和数据库校对规则:

·如果在数据库创建SQL中指定了CHARACTER SET X和COLLATE Y,那么采用字符集X和校对规则Y。如  CREATE DATABASE db_name DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci;

·如果指定了CHARACTER SET X而没有指定COLLATE Y,那么采用CHARACTER SET X和CHARACTER SET X的默认校对规则(查看什么是默认校对规则)。

·否则,采用服务器字符集和服务器校对规则。即MYSQL系统变量character_set_server和collation_server的值

默认数据库的字符集和校对规则通过character_set_database和 collation_database系统变量的值表示。无论何时默认数据库更改了,服务器都设置这两个变量的值。如果没有 默认数据库,这两个变量与相应的服务器级别的变量(character_set_server和collation_server)具有相同的值。

3)表字符集和校对

每一个表有一个表字符集和一个校对规则,它不能为空。MySQL按照下面的方式选择表字符集和校对规则:

· 如果在创建表的SQL语句中指定了CHARACTER SET X和COLLATE Y,那么采用CHARACTER SET X和COLLATE Y。如 CREATE TABLE A DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci

·如果指定了CHARACTER SET X而没有指定COLLATE Y,那么采用CHARACTER SET X和CHARACTER SET X的默认校对规则。

·否则,采用数据库字符集和数据库校对规则。

如果在列定义中没有指定列字符集和校对规则,则默认使用表字符集和校对规则。表字符集和校对规则是MySQL的扩展;在标准SQL中没有。

4)列字符集和校对

每一个“字符”列(即,CHAR、VARCHAR或TEXT类型的列)有一个列字符集和一个列校对规则,它不能为空。MySQL按照下面的方式选择列字符集和校对规则:

·如果指定了CHARACTER SET X和COLLATE Y,那么采用CHARACTER SET X和COLLATE Y。如

CREATE TABLE Table1

(

column1 VARCHAR(5) CHARACTER SET latin1 COLLATE latin1_german1_ci

);

·如果指定了CHARACTER SET X而没有指定COLLATE Y,那么采用CHARACTER SET X和CHARACTER SET X的默认校对规则。

·否则,采用表字符集和服务器校对规则。

5)连接字符集和校对

在客户端和服务器的连接处理中也涉及了字符集和校对规则变量。它们分别是character-set-client,character-set-connnection,character-set-results,collation-connection。

客户端发送SQL语句,例如查询,通过连接发送到服务器。服务器通过连接发送响应给客户端,例如结果集。

·客户端发送查询命令及请求数据,服务器要把这些数据当做什么字符集呢?

服务器使用character_set_client变量作为客户端发送的查询中使用的字符集。

·服务器接收到查询后应该转换为哪种字符集?

转换时,服务器使用character_set_connection和collation_connection系统变量。它将客户端发送的查询从 character_set_client指定的字符集转换为character_set_connection指定的字符集(除非字符串文字具有象_latin1或 _utf8的引介词)。collation_connection对比较文字字符串是重要的。对于列值的字符串比较,它不重要,因为列具有更高的校对规则优先级。

·服务器发送结果集或返回错误信息到客户端之前应该转换为哪种字符集?

character_set_results变量指示服务器返回查询结果到客户端使用的字符集。包括结果数据,例如列值和结果元数据(如列名)。

用户可以修改这几个系统变量的值。在MYSQL中,SET NAMES 'charset_name'能够影响连接字符集

SET NAMES 'x' 语句与下列三个语句等价:

mysql> SET character_set_client = x;mysql> SET character_set_results = x;mysql> SET character_set_connection = x;

7)字符串文字字符集和校对

每一字符串字符文字有一个字符集和一个校对规则,它不能为空。一个字符串文字可能有一个可选的字符集引用介词和COLLATE子句。如 SELECT _latin1'string' COLLATE latin1_danish_ci;

MySQL这样确定一个文字字符集和校对规则:

·如果指定了CHARACTER SET X和COLLATE Y,那么使用CHARACTER SET X和COLLATE Y。

·如果指定了CHARACTER SET X而没有指定COLLATE Y,那么使用CHARACTER SET X和CHARACTER SET X的默认校对规则。

·否则,使用通过character_set_connection和collation_connection系统变量给出的字符集和校对规则。

3、异常原因分析

通过上述对MySQL5字符集和校对规则的了解,就能够很清楚的分析出前言中的异常发生的原因了:

异常发生时的MySQL字符集和校对方式情况:

character_set_connection=utf8,校对方式为utf8默认校对方式

character_set_server=utf8,校对方式为utf8默认校对方式

character_set_database=utf8,校对方式为utf8默认校对方式

对于异常 Illegal mix of collations (gbk_chinese_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '=';

分析:其发生的SQL语句形如:SELECT COUNT(*) FROM urltable WHERE url='http://snap.xxx.com/中文';由于没有显示的指定字符串的字符集,因此MySQL采用 character_set_connection和collation_connection系统变量指定的值来处理,即utf8编码字符串,以 utf8的默认校对规则来处理'http://snap.xxx.com/中文';同时,由于列url是gbk编码的,因此MySQL对 url列采用的是gbk的字符集和gbk默认校对规则处理。因此在该SQL语句中'='两端的校对规则不一致,也就产生了先前的异常。

4、总结一下查询时的转换过程

1. MySQL Server收到请求时将请求数据从character_set_client转换为character_set_connection;

2. 进行内部操作前将请求数据从character_set_connection转换为内部操作字符集,其确定方法如下:

• 使用每个数据字段的CHARACTER SET设定值;

• 若上述值不存在,则使用对应数据表的DEFAULT CHARACTER SET设定值(MySQL扩展,非SQL标准);

• 若上述值不存在,则使用对应数据库的DEFAULT CHARACTER SET设定值;

• 若上述值不存在,则使用character_set_server设定值。

3. 将操作结果从内部操作字符集转换为character_set_results。

相关资料

• 字符(Character)是指人类语言中最小的表义符号。例如’A'、’B'等;

• 给定一系列字符,对每个字符赋予一个数值,用数值来代表对应的字符,这一数值就是字符的编码(Encoding)。例如,我们给字符’A'赋予数值0,给字符’B'赋予数值1,则0就是字符’A'的编码;

• 给定一系列字符并赋予对应的编码后,所有这些字符和编码对组成的集合就是字符集(Character Set)。例如,给定字符列表为{‘A’,'B’}时,{‘A’=>0, ‘B’=>1}就是一个字符集;

• 校对规则(Collation)是指在同一字符集内字符之间的比较规则;

• 确定校对规则后,才能在一个字符集上定义什么是等价的字符,以及字符之间的大小关系;

• 每个校对规则唯一对应一种字符集,但一个字符集可以对应多种字符序,其中有一个是默认字符序(Default Collation);

• MySQL中的校对规则名称遵从命名惯例:以字符序对应的字符集名称开头;以_ci(表示大小写不敏感)、_cs(表示大小写敏感)或_bin(表示按编码值比较)结尾。例如:在字符序“utf8_general_ci”下,字符“a”和“A”是等价的;

• 用introducer指定文本字符串的字符集:

– 格式为:[_charset] ‘string’ [COLLATE collation]

– 例如:

- SELECT _latin1 ‘string’;

- SELECT _utf8 ‘你好’ COLLATE utf8_general_ci;

– 由introducer修饰的文本字符串在请求过程中不经过多余的转码,直接转换为内部字符集处理。

参考:

http://www.laruence.com/2008/01/05/12.html

[转]MySQL5字符集支持及编码研究的更多相关文章

  1. 关于Unicode,字符集,字符编码,每个程序员都应该知道的事

    关于Unicode,字符集,字符编码,每个程序员都应该知道的事 作者:Jack47 李笑来的文章如何判断一个人是否聪明?中提到: 必要.清晰.且准确的概念,是一切思考的基石.所谓思考,很大程度上,就是 ...

  2. CodePage------Encoding 类支持的编码以及与这些编码关联的代码页(CodePage)

    Encoding 类 .NET Framework 4  表示字符编码. 继承层次结构 System.Object  System.Text.Encoding    System.Text.ASCII ...

  3. [转]字符集、字符编码、XML中的中文编码

    字符集.字符编码.XML中的中文编码 作为程序员的你是不是对于ASCII .UNICODE.GB2321.UTF-7.UTF-8等等不时出现在你面前的这些有着奇怪意义的词感到很讨厌呢,是不是总觉得好象 ...

  4. 字符集、字符编码、XML中的中文编码

    字符集.字符编码.XML中的中文编码 作为程序员的你是不是对于ASCII .UNICODE.GB2321.UTF-7.UTF-8等等不时出现在你面前的这些有着奇怪意义的词感到很讨厌呢,是不是总觉得好象 ...

  5. libiconv 支持的编码

    libiconv 支持的编码 php 中的 iconv() 函数常用来作编码转换用.作一些不同编码的动态数据的转换时常遇到一些未知编码的数据,这时 iconv() 支持那些编码转换就很重要. 刚开始, ...

  6. 字符集、字符编码、国际化、本地化简要总结(UNICODE/UTF/ASCII/GB2312/GBK/GB18030)

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 环境说明   普通的linux 和 普通的windows.    ...

  7. 字符集与字符编码 (charset & encoding)

    乱码是个大坑,相信每个人都遇过,而且是个绕不过去的坑.我理解每个程序员都应该写一篇编码相关的博文,梳理自己对这一块的理解,下面是我反复理解多次之后的学习小结. 1.从记事本的不同编码说起: 打开记事本 ...

  8. 刨根究底字符编码之十——Unicode字符集的字符编码方式CEF

    Unicode字符集的字符编码方式CEF 一.字符编码方式CEF的选择 1. 由于Unicode字符集非常大,有些字符的编号(码点值)需要两个或两个以上字节来表示,而要对这样的编号进行编码,也必须使用 ...

  9. 让ffmpeg支持10bit编码

    文章版权由作者柯O德尔和博客园共有,请尊重并支持原创,若转载请于明显处标明出处:http://www.cnblogs.com/koder/ 最近因为工作需要,要进行265 10bit编码,于是从ffm ...

随机推荐

  1. AJPFX: Java基础多线程(一)

    多线程是Java学习的非常重要的方面,是每个Java程序员必须掌握的基本技能.本文只是多线程细节.本质的总结,并无代码例子入门,不适合初学者理解.初学者学习多线程,建议一边看书.看博文,以便写代码尝试 ...

  2. 前端--1、HTML基础

    web服务 处于应用层的http协议负责的数据传输与解析.位于socket上层,用socket传输http数据时需要在消息开头处声明是http协议/相应http版本 状态码 状态码含义 \r\n\r\ ...

  3. GatewayWorker+Laravel demo

    GatewayWorker 结合 Laravel 使用的简单案例,重点是在Laravel中使用GatewayClient发送消息 主要流程:GatewayWorker主要负责推送消息给客户端但不接受客 ...

  4. Godaddy域名301跳转问题处理

    前言:Godaddy的域名301跳转一共有六步,详情见以下步骤: 第一步: 第二步:找到你的域名,并点击DNS 第三步:点击添加 第四步:添加解析ip地址 第五步:域名转址,也就是301跳转 第六步: ...

  5. SQL优化基础 使用索引(一个小例子)

    按照本文操作和体会,会对sql优化有个基本最简单的了解,其他深入还需要更多资料和实践的学习: 1. 建表: 复制代码代码如下: create table site_user ( id int IDEN ...

  6. 【分享】4412开发板POP烧写ubuntu出错,如何挂载emmc分区解决方法

    本文转自:http://bbs.topeetboard.com 平台:4412精英版系统:ubuntu系统 按照教程烧写ubuntu文件系统,TF卡和EMMC分区都完成(总之之前的操作试了几遍都是没问 ...

  7. ZooKeeper系列(三)

    前面虽然配置了集群模式的Zookeeper,但是为了方面学建议在伪分布式模式的Zookeeper学习Zookeeper的shell命令. 一.Zookeeper的四字命令 Zookeeper支持某些特 ...

  8. Jenkins总结(ant+jmeter+java)

    1.jdk与ant都需要在Jenkins-->系统管理-->全局工具配置里面配置各自的安装目录 2.修改Jenkins配置文件后,通过命令行重启: source /etc/profile ...

  9. 第3节 hive高级用法:14、hive的数据压缩

    六.hive的数据压缩 在实际工作当中,hive当中处理的数据,一般都需要经过压缩,前期我们在学习hadoop的时候,已经配置过hadoop的压缩,我们这里的hive也是一样的可以使用压缩来节省我们的 ...

  10. hdfs深入:05、hdfs中的fsimage和edits的合并过程

    6.4.secondarynameNode如何辅助管理FSImage与Edits文件 ①:secnonaryNN通知NameNode切换editlog ②:secondaryNN从NameNode中获 ...