前言

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

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. 把sed当作命令解释器使用

    [root@sishen ~]# vim script.sed #!/bin/sed -f #交换第一列和第二列 s/\([^,]*\),\([^,]*\),\(.*\).*/\2,\1, \3/g ...

  2. java课程设计全程实录——第2天

    [反思] 今天主要完成JDBC数据的连接,查阅了大量博客和书籍,繁琐而细碎.但所幸还是连上了. [日常烦心事] 下午准备用idea连测试连接的,结果电脑跑不动....CPU一度100%居高不下,ide ...

  3. git介绍与使用

    git是去中心化版本管理工具,项目创建一个远程版本,将其clone到本地,会在本地创建一个本地仓,一个开发项目,在没有网络的时候依然可以提交修改到本地仓,当有网络的时候再提交到远程仓库.git可以快速 ...

  4. Python学习 Day 5 高阶函数 map/reduce filter sorter 返回函数 匿名函数 装饰器 偏函数

    高阶函数Higher-orderfunction 变量可以指向函数 >>> abs #abs(-10)是函数调用,而abs是函数本身 <built-in function ab ...

  5. SQL将查询出来的多列的值拼接成一个字符串

    -- 单列拼接,先查出一行,再加上逗号,接着拼接 查出的下一行 SELECT GROUP_CONCAT(user_id) FROM user; -- result 160,160,160,196 -- ...

  6. 黑马程序员----java基础:异常

    dff ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 经常写程序的人对try...catch...finally语句肯定是不陌生的了.但是好多 ...

  7. 如何优化LIMIT

    首先我们先创建个数据表做测试 表名 test (id(int) , name(var char) , content(text) , pid(int) ) 往里面倒几百万条数据进去做测试. 我们都知道 ...

  8. C# 如何发送Http请求

    HttpSender是一个用于发送Http消息的轻量C#库,使用非常简单,只需要一两行代码,就能完成Http请求的发送 使用 Nuget,搜索 HttpSender 就能找到这个库 这个库的命名空间是 ...

  9. HTML5页面直接调用百度地图API,获取当前位置,直接导航目的地

    <!DOCTYPE html> <html lang="zh-cmn-Hans"> <meta charset="UTF-8"&g ...

  10. js获取当前位置

    <!DOCTYPE html><html><head><meta name="viewport" content="initia ...