字符集介紹及mysql數據庫編碼轉換

http://wushank.blog.51cto.com/3489095/1341592


一、字符集介紹:

1、ASCII

ASCII是英文American Standard Code for Information Interchange的縮寫,美國標準信息交換代碼是由美國國家標準學會(American National Standard Institute , ANSI )制定的,標準的單字節字符編碼方案,用於基於文本的數據。是基於拉丁字母的一套電腦編碼系統。它主要用於顯示現代英語和其他西歐語言。它是現今最通用的單字節編碼系統,並等同於國際標準ISO/IEC 646。

    ASCII 碼使用指定的7 位或8 位二進制數組合來表示128 或256 種可能的字符。標準ASCII 碼也叫基礎ASCII碼,使用7 位二進制數來表示所有的大寫和小寫字母,數字0 到9、標點符號, 以及在美式英語中使用的特殊控制字符

  其中:

0~31及127(共33個)是控制字符或通信專用字符(其餘爲可顯示字符),如控制符:LF(換行)、CR(回車)、FF(換頁)、DEL(刪除)、BS(退格)、BEL(響鈴)等;通信專用字符:SOH(文頭)、EOT(文尾)、ACK(確認)等;ASCII值爲8、9、10 和13 分別轉換爲退格、製表、換行和回車字符。它們並沒有特定的圖形顯示,但會依不同的應用程序,而對文本顯示有不同的影響。
32~126(共95個)是字符(32是空格),其中48~57爲0到9十個阿拉伯數字

65~90爲26個大寫英文字母,97~122號爲26個小寫英文字母,其餘爲一些標點符號、運算符號等。


143013265.jpg

擴展ASCII 字符是從128 到255(0x80-0xff)的字符。


2、GBK

GBK即漢字內碼擴展規範,K爲擴展的漢語拼音中“擴”字的聲母。英文全稱Chinese Internal Code Specification。GBK編碼標準兼容GB2312,共收錄漢字21003個、符號883個,並提供1894個造字碼位,簡、繁體字融於一庫。GB2312碼是中華人民共和國國家漢字信息交換用編碼,全稱《信息交換用漢字編碼字符集——基本集》,1980年由國家標準總局發佈。基本集共收入漢字6763個和非漢字圖形字符682個,通行於中國大陸。新加坡等地也使用此編碼。GBK是對GB2312-80的擴展,也就是CP936字碼表 (Code Page 936)的擴展(之前CP936和GB 2312-80一模一樣)。


3、latin1

Latin1是ISO-8859-1的別名,有些環境下寫作Latin-1。
ISO-8859-1
ISO-8859-1編碼是單字節編碼,向下兼容ASCII,其編碼範圍是0x00-0xFF,0x00-0x7F之間完全和ASCII一致,0x80-0x9F之間是控制字符,0xA0-0xFF之間是文字符號。
ISO-8859-1收錄的字符除ASCII收錄的字符外,還包括西歐語言、希臘語、泰語、阿拉伯語、希伯來語對應的文字符號。歐元符號出現的比較晚,沒有被收錄在ISO-8859-1當中。

因爲ISO-8859-1編碼範圍使用了單字節內的所有空間,在支持ISO-8859-1的系統中傳輸和存儲其他任何編碼的字節流都不會被拋棄。換言之,把其他任何編碼的字節流當作ISO-8859-1編碼看待都沒有問題。這是個很重要的特性,MySQL數據庫默認編碼是Latin1就是利用了這個特性。ASCII編碼是一個7位的容器,ISO-8859-1編碼是一個8位的容器。


4、UTF-8

UTF-8(8-bit Unicode Transformation Format)是一種針對Unicode的可變長度字符編碼,又稱萬國碼。由Ken Thompson於1992年創建。現在已經標準化爲RFC 3629。UTF-8用1到4個字節編碼UNICODE字符。用在網頁上可以同一頁面顯示中文簡體繁體及其它語言(如日文,韓文)


UTF-8以字節爲單位對Unicode進行編碼。從Unicode到UTF-8的編碼方式如下:
Unicode編碼(十六進制) 
UTF-8 字節流(二進制)
000000 - 00007F
0xxxxxxx
000080 - 0007FF
110xxxxx 10xxxxxx
000800 - 00FFFF
1110xxxx 10xxxxxx 10xxxxxx
010000 - 10FFFF
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
UTF-8的特點是對不同範圍的字符使用不同長度的編碼。對於0x00-0x7F之間的字符,UTF-8編碼與ASCII編碼完全相同。UTF-8編碼的最大長度是4個字節。從上表可以看出,4字節模板有21個x,即可以容納21位二進制數字。Unicode的最大碼位0x10FFFF也只有21位。
例1:“漢”字的Unicode編碼是0x6C49。0x6C49在0x0800-0xFFFF之間,使用用3字節模板了:1110xxxx 10xxxxxx 10xxxxxx。將0x6C49寫成二進制是:0110 1100 0100 1001, 用這個比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。
例2:Unicode編碼0x20C30在0x010000-0x10FFFF之間,使用用4字節模板了:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx。將0x20C30寫成21位二進制數字(不足21位就在前面補0):0 0010 0000 1100 0011 0000,用這個比特流依次代替模板中的x,得到:11110000 10100000 10110000 10110000,即F0 A0 B0 B0。


二、MySQL字符集設置

1、 系統變量:

character_set_server:默認的內部操作字符集

character_set_client:客戶端來源數據使用的字符集

character_set_connection:連接層字符集

character_set_results:查詢結果字符集

character_set_database:當前選中數據庫的默認字符集

character_set_system:系統元數據(字段名等)字符集

還有以collation_開頭的同上面對應的變量,用來描述字符序。


2、MySQL的字符集支持(Character Set Support)有兩個方面:

  1.字符集(Character set)和排序方式(Collation)。
  對於字符集的支持細化到四個層次:

  服務器(server),數據庫(database),數據表(table)和連接(connection)。

  MySQL對於字符集的指定可以細化到一個數據庫,一張表,一列,應該用什麼字符集。

  但是,傳統的程序在創建數據庫和數據表時並沒有使用那麼複雜的配置,它們用的是默認的配置,那麼,默認的配置從何而來呢?

  (1)編譯MySQL 時,指定了一個默認的字符集,這個字符集是 latin1;
  (2)安裝MySQL 時,可以在配置文件 (my.cnf) 中指定一個默認的的字符集,如果沒指定,這個值繼承自編譯時指定的;
  (3)啓動mysqld 時,可以在命令行參數中指定一個默認的的字符集,如果沒指定,這個值繼承自配置文件中的配置,此時character_set_server被設定爲這個默認的字符集;
  (4)當創建一個新的數據庫時,除非明確指定,這個數據庫的字符集被缺省設定爲character_set_server;
  (5)當選定了一個數據庫時,character_set_database被設定爲這個數據庫默認的字符集;
  (6)在這個數據庫裏創建一張表時,表默認的字符集被設定爲character_set_database,也就是這個數據庫默認的字符集;
  (7)當在表內設置一欄時,除非明確指定,否則此欄缺省的字符集就是表默認的字符集;

  簡單的總結一下,如果什麼地方都不修改,那麼所有的數據庫的所有表的所有欄位的都用 latin1 存儲,不過我們如果安裝 MySQL,一般都會選擇多語言支持,也就是說,安裝程序會自動在配置文件中把default_character_set設置爲 UTF-8,這保證了缺省情況下,所有的數據庫的所有表的所有欄位的都用 UTF-8 存儲。


2.查看默認字符集(默認情況下,mysql的字符集是latin1(ISO_8859_1)通常,查看系統的字符集和排序方式的設定可以通過下面的兩條命令:


mysql> SHOW VARIABLES LIKE 'character%';
+--------------------------+---------------------------------+
| Variable_name            | Value                           |
+--------------------------+---------------------------------+
| character_set_client     | latin1                          |
| character_set_connection | latin1                          |
| character_set_database   | latin1                          |
| character_set_filesystem | binary                          |
| character_set_results    | latin1                          |
| character_set_server     | latin1                          |
| character_set_system     | utf8                            |
| character_sets_dir       | D:"mysql-5.0.37"share"charsets" |
+--------------------------+---------------------------------+

mysql> SHOW VARIABLES LIKE 'collation_%';
+----------------------+-----------------+
| Variable_name        | Value           |
+----------------------+-----------------+
| collation_connection | utf8_general_ci |
| collation_database   | utf8_general_ci |
| collation_server     | utf8_general_ci |
+----------------------+-----------------+


從上例中我們可以看出字符集utf8,其中默認的排序方式爲utf8_general_ci
排序方式的命名規則爲:字符集名字_語言_後綴,其中各個典型後綴的含義如下:
1)_ci:不區分大小寫的排序方式
2)_cs:區分大小寫的排序方式
3)_bin:二進制排序方式,大小比較將根據字符編碼,不涉及人類語言,因此_bin的排序方式不包含人類語言

3、MySQL中的字符集轉換過程

 (1). MySQL Server收到請求時將請求數據從character_set_client轉換爲character_set_connection;

 (2). 進行內部操作前將請求數據從character_set_connection轉換爲內部操作字符集,其確定方法如下:

使用每個數據字段的CHARACTER SET設定值;

若上述值不存在,則使用對應數據表的DEFAULT CHARACTERSET設定值(MySQL擴展,非SQL標準);

若上述值不存在,則使用對應數據庫的DEFAULT CHARACTERSET設定值;

若上述值不存在,則使用character_set_server設定值。

 (3). 將操作結果從內部操作字符集轉換爲character_set_results。

151539928.jpg


4、常見問題解析

向默認字符集爲utf8的數據表插入utf8編碼的數據前沒有設置連接字符集,查詢時設置連接字符集爲utf8

插入時根據MySQL服務器的默認設置,character_set_client、character_set_connection和character_set_results均爲latin1;

插入操作的數據將經過latin1=>latin1=>utf8的字符集轉換過程,這一過程中每個插入的漢字都會從原始的3個字節變成6個字節保存;

查詢時的結果將經過utf8=>utf8的字符集轉換過程,將保存的6個字節原封不動返回,產生亂碼……

151540330.jpg


向默認字符集爲latin1的數據表插入utf8編碼的數據前設置了連接字符集爲utf8

插入時根據連接字符集設置,character_set_client、character_set_connection和character_set_results均爲utf8;

插入數據將經過utf8=>utf8=>latin1的字符集轉換,若原始數據中含有\u0000~\u00ff範圍以外的Unicode字 符,會因爲無法在latin1字符集中表示而被轉換爲“?”(0×3F)符號,以後查詢時不管連接字符集設置如何都無法恢復其內容了。

151540780.jpg


5、檢測字符集問題的一些手段

SHOW CHARACTER SET;

SHOW COLLATION;

SHOW VARIABLES LIKE ‘character%’;

SHOW VARIABLES LIKE ‘collation%’;

SQL函數HEX、LENGTH、CHAR_LENGTH

SQL函數CHARSET、COLLATION


6、使用MySQL字符集時的建議

建立數據庫/表和進行數據庫操作時儘量顯式指出使用的字符集,而不是依賴於MySQL的默認設置,否則MySQL升級時可能帶來很大困擾;

數據庫和連接字符集都使用latin1時雖然大部分情況下都可以解決亂碼問題,但缺點是無法以字符爲單位來進行SQL操作,一般情況下將數據庫和連接字符集都置爲utf8是較好的選擇;

使用mysql C API時,初始化數據庫句柄後馬上用mysql_options設定MYSQL_SET_CHARSET_NAME屬性爲utf8,這樣就不用顯式地用 SET NAMES語句指定連接字符集,且用mysql_ping重連斷開的長連接時也會把連接字符集重置爲utf8;

對於mysql PHP API,一般頁面級的PHP程序總運行時間較短,在連接到數據庫以後顯式用SET NAMES語句設置一次連接字符集即可;但當使用長連接時,請注意保持連接通暢並在斷開重連後用SET NAMES語句顯式重置連接字符集。


7、其他注意事項

my.cnf中的default_character_set設置隻影響mysql命令連接服務器時的連接字符集,不會對使用libmysqlclient庫的應用程序產生任何作用!

對字段進行的SQL函數操作通常都是以內部操作字符集進行的,不受連接字符集設置的影響。

SQL語句中的裸字符串會受到連接字符集或introducer設置的影響,對於比較之類的操作可能產生完全不同的結果,需要小心!


三、修改mysql默認字符集

下面介紹下幾個MYSQL命令:
    1.show character set;或show char set;
     查看數據庫支持的所有字符集
    2.status;或\s;
     查看當前狀態 裏面包括當然的字符集設置
    3.show variables like 'char%';
     查看系統字符集設置,包括所有的字符集設置
    4.show table status from sqlstudy like '%countries%';
     查看sqlstudy數據庫中表的字符集設置
    5.show full columns from countries;
     查看錶列的字符集設置,關鍵是在同一個表中,每列可以設置成不同的字符集
知道怎麼查看字符集了,下面我來說下如何設置這些字符集(當然全是我這幾天從網上整理的,呵呵)
    1.修改服務器級
        a. 臨時更改:
            mysql>SET GLOBAL character_set_server=utf8;
       b. 永久更改:
            修改my.cnf文件
          [mysqld]
          default-character-set=utf8
   2.修改數據庫級
         a. 臨時更改:
             mysql>SET GLOBAL character_set_database=utf8;
        b. 永久更改:
             改了服務器級就可以了
    3.修改表級
         mysql>ALTER TABLE table_name DEFAULT CHARSET utf8;
        更改了後永久生效
    4.修改列級
          修改示例:
         mysql>alter
table `products` change `products_model` `products_model` varchar( 20 )
        character set  utf8 collate utf8_general_ci null default null;
        更改了後永久生效
     5.更改連接字符集
          a. 臨時更改:
              mysql> set names utf8;
         b. 永久更改:
              修改my.cnf文件
            在[client]中增加:
              default-character-set=utf8
執行SQL語句時信息的路徑是這樣的
信息輸入路徑:client→connection→server;
信息輸出路徑:server→connection→results.


四、mysql字符集轉換實例:

以原來的字符集爲latin1爲例,升級成爲utf8的字符集。原來的表: databasename (default charset=latin1),新表:new_databasename(default charset=utf8)。


mysql> show create database databasename;
+--------------+-------------------------------------------------------------------------+
| Database | Create Database |
+--------------+-------------------------------------------------------------------------+
| databasename | CREATE DATABASE `databasename` /*!40100 DEFAULT CHARACTER SET latin1 */ |
+--------------+-------------------------------------------------------------------------+
1 row in set (0.00 sec)



背景:某個系統的mysql數據庫dnname採用默認的latin1字符集,系統升級需要將所有數據轉換成utf-8格式,目標數據庫爲newdbname(建庫時使用utf8)

方法一:

1、命令行執行:mysqldump --opt -hlocalhost -uroot -p*** --default-character-set=lantin1 dbname > /usr/local/dbname.sql

2、將 dbname.sql文件中的create table語句的CHARSET=latin1改爲CHARSET=utf8

3、在dbname.sql文件中的insert語句之前加一條'set names utf8;'

4、將dbname.sql轉碼爲utf-8格式,建議使用UltraEditor,可以直接使用該編輯器的'轉換->ASCII到UTF-8(Unicode編輯)',或者將文件另存爲UTF-8(無BOM)格式

5、創建新數據庫
CREATE DATABASE new_dbname CHARACTER SET utf8 COLLATE utf8_general_ci;

6、命令行執行:mysql -hlocalhost -uroot -p*** --default-character-set=utf8 new_dbname < /usr/local/dbname.sql

總結:這種方法有個致命之處就是當數據中有大量中文字符和其他特殊符號字符時,很有可能導致在[步驟五]時報錯導致無法正常導入數據,如果數據庫比較大可以分別對每張表執行上述步驟


方法二(推薦大家使用):

爲了解決第一種方法中總結時說到的問題,在網上苦苦查找了一天資料才東拼西湊的搞出一個比較穩妥的解決方法

1、將待導出的數據表的表結構導出(可以用Phpmyadmin、mysqldump等,很簡單就不說了),然後將導出的create table語句的CHARSET=latin1改爲CHARSET=utf8,在目標庫newdbname中執行該create table語句把表結構建好,接下來開始導出-導入數據

2、命令行:進入mysql命令行下,mysql -hlocalhost -uroot -p*** dbname

3、執行SQL select * from tbname into outfile '/usr/local/tbname.sql';

4、將tbname.sql轉碼爲utf-8格式,建議使用UltraEditor,可以直接使用該編輯器的'轉換->ASCII到UTF-8(Unicode編輯)',或者將文件另存爲UTF-8(無BOM)格式

5、在mysql命令行下執行語句 set character_set_database=utf8;  注:設置mysql的環境變量,這樣mysql在下一步讀取sql文件時將以utf8的形式去解釋該文件內容

6、在mysql命令行下執行語句 load data infile 'tbname.sql' into table newdbname.tbname;

注意:千萬不要忘了第四步

採用第二種方法,所有數據均正常導入,且格式轉換成功沒有亂碼,要注意最好是源字符的超級,或者確定比源字符集的字庫更大。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章