簡單明白徹底解決 MySQL 中文編碼問題

簡單明白徹底解決 MySQL 中文編碼問題

1. 問題重現(xiàn)

mysql> create database school;
mysql> use school;
mysql> create table student(name varchar(10));
mysql> insert into student values("Clarke");
mysql> select * from student;
+--------+
| name   |
+--------+
| Clarke |
+--------+
mysql> insert into student values("唐三");

# 插入中文失敗
ERROR 1366 (HY000): Incorrect string value: '\xE5\x94\x90\xE4\xB8\x89' for column 'name' at row 1

2. 分析和解決

2.1 數(shù)據(jù)庫編碼設(shè)置

2.1.1 查看 MySQL 程序編碼設(shè)置

mysql> show variables like 'char%';
+--------------------------+----------------------------+
| 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       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

可以看到佣蓉,設(shè)置里有很多的編碼設(shè)置是 latin1乔煞,這個(gè)編碼是無法正確顯示中文的,如果你的設(shè)置也是這樣,這就是導(dǎo)致中文編碼問題的可能原因延欠。

關(guān)于這些設(shè)置的含義:

option desc
character_set_client 客戶端使用的字符編碼饮睬,如果客戶端連接時(shí)沒有設(shè)置,或者服務(wù)端已配置為忽略客戶端的設(shè)置
character_set_connection 客戶端設(shè)置連接數(shù)據(jù)庫時(shí)的字符編碼纱新,如果客戶端沒有指明展氓,則連接數(shù)據(jù)庫使用該設(shè)置的編碼
character_set_database 當(dāng)前選中數(shù)據(jù)庫的默認(rèn)字符編碼,如果沒有選中數(shù)據(jù)庫(use <database>)脸爱,則和 character_set_server 的值一致
character_set_filesystem 文件系統(tǒng)的編碼格式遇汞,把操作系統(tǒng)上的文件名轉(zhuǎn)化成此字符集,即把 character_set_client轉(zhuǎn)換character_set_filesystem簿废, 默認(rèn)binary是不做任何轉(zhuǎn)換的
character_set_results 數(shù)據(jù)庫給客戶端返回時(shí)使用的編碼格式空入,如果客戶端連接時(shí)沒有指明,則使用該編碼
character_set_server 數(shù)據(jù)庫服務(wù)器默認(rèn)編碼格式族檬,創(chuàng)建數(shù)據(jù)庫時(shí)默認(rèn)使用
character_set_system 數(shù)據(jù)庫系統(tǒng)使用的編碼格式歪赢,這個(gè)值一直是utf8,不需要設(shè)置单料,它是為存儲(chǔ)系統(tǒng)元數(shù)據(jù)的編碼格式
character_sets_dir 這個(gè)變量是字符集安裝的目錄

更多說明:MySQL doc - 5.1.7 Server System Variables

2.1.2 修改編碼設(shè)置

編碼設(shè)置中我們需要關(guān)注的是下面 5 個(gè)字符編碼設(shè)置:

# 服務(wù)端相關(guān)
character_set_server
character_set_database #當(dāng)前選中數(shù)據(jù)庫的編碼埋凯,這個(gè)設(shè)置不需要手動(dòng)修改?

# 客戶端相關(guān)
character_set_client
character_set_connection
character_set_results

修改編碼設(shè)置的方式有三種点楼。

方式1: session 范圍修改

mysql> set character_set_server=utf8mb4

建議使用 utf8mb4 編碼而不是 utf8,因?yàn)?MySQL 的 utf8 編碼有點(diǎn)小問題白对,可以自行百度 MySQL 中 utf8 和 utf8mb4 的區(qū)別

這種修改方式是 session 范圍的盟步,也就是當(dāng)前的 MySQL 連接結(jié)束后,設(shè)置就失效了躏结。

其他幾個(gè)編碼設(shè)置也一樣修改却盘。

方式2: global 范圍修改

mysql> set global character_set_server=utf8mb4

global 范圍下的修改,重新連接依然有效媳拴,直到 MySQL 服務(wù)端重啟黄橘。

方式3: 修改配置文件

想要編碼設(shè)置在 MySQL 服務(wù)端重啟后依然生效,可以修改配置文件屈溉。

不同平臺(tái)的配置文件位置不一樣塞关,可以通過下面命令查看:

?  ~ mysql --verbose --help | grep my.cnf

/etc/my.cnf /etc/mysql/my.cnf /usr/local/mysql/etc/my.cnf ~/.my.cnf

更多說明: MySQL 官方文檔:4.2.2.2 Using Option Files

除了~/.my.cnf文件是用戶級(jí)別的外,其他幾個(gè)位置都是系統(tǒng)級(jí)別的子巾,如果該位置沒有my.cnf文件帆赢,就新建一個(gè)文本文件,命名為 my.cnf线梗。

windows 系統(tǒng)下椰于,這個(gè)文件叫 my.ini

my.cnf文件中添加以下內(nèi)容:

[mysqld]
character_set_server=utf8mb4
collation_server=utf8mb4_unicode_ci 
[client]
default_character-set=utf8mb4

更多信息參考: A.11 MySQL 8.0 FAQ: MySQL Chinese, Japanese, and Korean Character Sets

配置項(xiàng)說明:

  • character-set-server 設(shè)置影響 character_set_server 的值仪搔,character_set_database 的值在未選中當(dāng)前數(shù)據(jù)庫的情況下下瘾婿,默認(rèn)跟隨 character_set_server 的值。

  • default-character-set 影響 character_set_client, character_set_connection, character_set_results 三者的值烤咧。

在 MySQL 連接終端中執(zhí)行 SET NAMES <charset>也是影響的 character_set_client, character_set_connection, character_set_results 三者的值

  • collation_server 影響 orderby 的排序結(jié)果偏陪,建議設(shè)置 character-set-server 的同時(shí)也要設(shè)置

關(guān)于 character_set_server 和 collation_server: MySQL doc - sysvar_character_set_server

修改配置文件后重啟 MySQL,再查看下編碼設(shè)置煮嫌,

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     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

可以看到已經(jīng)生效了笛谦,5 個(gè)相關(guān)設(shè)置已經(jīng)修改為 utf8mb4。

三種修改方式昌阿,優(yōu)先選擇修改配置文件饥脑,其次的選擇或者想要靈活設(shè)置的話,可以在終端會(huì)話中設(shè)置宝泵。

2.2 已創(chuàng)建的數(shù)據(jù)庫的編碼

如果上面的配置已經(jīng)修改完成好啰,可能仍然有中文編碼問題,因?yàn)閷?duì)于已經(jīng)創(chuàng)建完成的數(shù)據(jù)庫和表儿奶,它的編碼在創(chuàng)建時(shí)已經(jīng)確定了框往,前面的配置項(xiàng)(character_set_server)已經(jīng)不能影響了,需要逐個(gè)修改相應(yīng)的數(shù)據(jù)庫闯捎,表椰弊,列许溅。

2.2.1 具體數(shù)據(jù)庫的編碼

查看完整的數(shù)據(jù)庫創(chuàng)建語句:

mysql> show create database school;
+----------+-------------------------------------------------------------------+
| Database | Create Database                                                   |
+----------+-------------------------------------------------------------------+
| school   | CREATE DATABASE `school` /*!40100 DEFAULT CHARACTER SET latin1 */ |
+----------+-------------------------------------------------------------------+

可以看到數(shù)據(jù)庫 school 的默認(rèn)編碼仍然是 latin1,改起:

mysql> alter database school character set 'utf8mb4';

mysql> show create database school;
+----------+--------------------------------------------------------------------+
| Database | Create Database                                                    |
+----------+--------------------------------------------------------------------+
| school   | CREATE DATABASE `school` /*!40100 DEFAULT CHARACTER SET utf8mb4 */ |
+----------+--------------------------------------------------------------------+

2.2.2 表的編碼

在前一節(jié)秉版,數(shù)據(jù)庫 school 的默認(rèn)編碼已經(jīng)修改為 utf8mb4贤重,接下來看數(shù)據(jù)表的默認(rèn)編碼:

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

看到數(shù)據(jù)表 student 的默認(rèn)編碼仍然是 latin1,再改起:

mysql> alter table student character set 'utf8mb4';
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show create table student;
+---------+-------------------------------------------------------------------------------------------------------------------------+
| Table   | Create Table                                                                                                            |
+---------+-------------------------------------------------------------------------------------------------------------------------+
| student | CREATE TABLE `student` (
  `name` varchar(10) CHARACTER SET latin1 DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
+---------+-------------------------------------------------------------------------------------------------------------------------+

2.2.3 列的編碼

在上一節(jié)可以看到清焕,數(shù)據(jù)表 student 的默認(rèn)編碼已經(jīng)修改為 utf8mb4并蝗,但是列 name 的編碼還是 latin1,改起秸妥!

mysql> alter table `student` change `name` `name` text character set 'utf8mb4';
Query OK, 1 row affected (0.04 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> show create table student;
+---------+--------------------------------------------------------------------------------+
| Table   | Create Table                                                                   |
+---------+--------------------------------------------------------------------------------+
| student | CREATE TABLE `student` (
  `name` text
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
+---------+--------------------------------------------------------------------------------+

到這里滚停,對(duì)于已經(jīng)存在的數(shù)據(jù)庫,修改完成粥惧,再插入中文試試:

mysql> insert into student value("昊天");
Query OK, 1 row affected (0.00 sec)

mysql> select * from student;
+--------+
| name   |
+--------+
| Clarke |
| 昊天   |
+--------+
2 rows in set (0.00 sec)

成功键畴!到此,中文編碼的問題就解決了突雪。

2.3 防御性編碼

為了防止意外的情況發(fā)生起惕,我們可以采取更健壯的防御性編碼的方式,哪怕數(shù)據(jù)庫服務(wù)端的編碼設(shè)置不正確咏删,我們?nèi)匀豢梢圆迦胫形臄?shù)據(jù)惹想。

具體就是在創(chuàng)建數(shù)據(jù)表的時(shí)候指定默認(rèn)編碼:

mysql> show variables like 'char%';
+--------------------------+----------------------------+
| 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       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

# 指定存儲(chǔ)引擎,編碼饵婆,排序規(guī)則
mysql> create table course(name varchar(32)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Query OK, 0 rows affected (0.03 sec)

mysql> insert into course value('高數(shù)');
Query OK, 1 row affected (0.01 sec)

mysql> select * from course;
+--------+
| name   |
+--------+
| 高數(shù)   |
+--------+
1 row in set (0.00 sec)

或者直接在創(chuàng)建數(shù)據(jù)庫的時(shí)候就指定編碼:

mysql> create database school DEFAULT CHARACTER SET utf8mb4;

3. 總結(jié)

解決 MySQL 中文編碼問題的步驟:

  1. 查看數(shù)據(jù)庫編碼設(shè)置

  2. 修改編碼設(shè)置勺馆,在終端中修改設(shè)置項(xiàng),或者修改配置文件 my.cnf 以永久生效

  3. 對(duì)于之前創(chuàng)建的數(shù)據(jù)庫侨核,修改數(shù)據(jù)庫,數(shù)據(jù)表灌灾,數(shù)據(jù)列的默認(rèn)編碼

最佳實(shí)踐:防御性編碼搓译,在數(shù)據(jù)庫創(chuàng)建語句中指定默認(rèn)編碼。

參考:

MySQL 5.7 官方文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末锋喜,一起剝皮案震驚了整個(gè)濱河市些己,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嘿般,老刑警劉巖段标,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異炉奴,居然都是意外死亡逼庞,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門瞻赶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赛糟,“玉大人派任,你說我怎么就攤上這事¤的希” “怎么了掌逛?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長司倚。 經(jīng)常有香客問我豆混,道長,這世上最難降的妖魔是什么动知? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任崖叫,我火速辦了婚禮,結(jié)果婚禮上拍柒,老公的妹妹穿的比我還像新娘心傀。我一直安慰自己,他們只是感情好拆讯,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布脂男。 她就那樣靜靜地躺著,像睡著了一般种呐。 火紅的嫁衣襯著肌膚如雪宰翅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天爽室,我揣著相機(jī)與錄音汁讼,去河邊找鬼。 笑死阔墩,一個(gè)胖子當(dāng)著我的面吹牛嘿架,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播啸箫,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼耸彪,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了忘苛?” 一聲冷哼從身側(cè)響起蝉娜,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎扎唾,沒想到半個(gè)月后召川,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡胸遇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年荧呐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡坛增,死狀恐怖获雕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情收捣,我是刑警寧澤届案,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站罢艾,受9級(jí)特大地震影響楣颠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜咐蚯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一童漩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧春锋,春花似錦矫膨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至呐萌,卻和暖如春馁痴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肺孤。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來泰國打工罗晕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人赠堵。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓小渊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親顾腊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子粤铭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 前段時(shí)間公司內(nèi)部博客上凱哥分享了一篇關(guān)于mysql字符集編碼的文章,之前我對(duì)mysql字符集一塊基本沒有深究過,看...
    __七把刀__閱讀 6,440評(píng)論 14 18
  • 顧穎17021223250 轉(zhuǎn)載自https://blog.csdn.net/qingqing7/article/...
    大貓_23fe閱讀 1,090評(píng)論 0 2
  • 什么是數(shù)據(jù)庫? 數(shù)據(jù)庫是存儲(chǔ)數(shù)據(jù)的集合的單獨(dú)的應(yīng)用程序杂靶。每個(gè)數(shù)據(jù)庫具有一個(gè)或多個(gè)不同的API,用于創(chuàng)建酱鸭,訪問吗垮,管理...
    chen_000閱讀 4,035評(píng)論 0 19
  • 摘要:在MySQL的使用過程中,了解字符集凹髓、字符序的概念烁登,以及不同設(shè)置對(duì)數(shù)據(jù)存儲(chǔ)、比較的影響非常重要。不少同學(xué)在日...
    暖夏未眠丶閱讀 784評(píng)論 0 2
  • 最近,在項(xiàng)目組使用的mysql數(shù)據(jù)庫中狼牺,插入數(shù)據(jù)出現(xiàn)亂碼羡儿,關(guān)于這個(gè)問題做了下總結(jié),我們從最基本的地方說起是钥,到錯(cuò)誤產(chǎn)...
    陳強(qiáng)Mike曉閱讀 858評(píng)論 0 0