搜尋
首頁資料庫mysql教程MySQL乱码问题终极指南_MySQL

mysql的字符集设置众多,从客户端到连接到结果集,从服务器到库到表到列,都可以设置字符集,灵活很强大,但就是很容易出问题,如果不了解其机制,很容易就出现乱码问题。

为了让大家尽量在工作中少受或者不受乱码的困扰,这里我结合之前其它同学在论坛的发帖,并结合自己的理解和实践,详细分析总结了一下,以飨各位看官。

关于字符集和乱码的基础知识这里就不详细说明了(请自行搜索),但有一个问题需要特别强调一下:乱码是怎么产生的?
这个问题相信很多同学都是模棱两可,或者没有认真想过,反正理解就是”字符编码“不对导致乱码,但没有真正想过为什么”字符编码“会导致乱码。
答案其实很简单:“转换导致乱码”!
根据这个原则来判断,各种情况就很简单了:

1)数据传送过程中不会导致乱码
2)数据存储不会导致乱码
3)数据输入和输出(包括显示)可能导致乱码
4)数据接收和发送可能导致乱码

更详细的解释:转换导致乱码是指本来是A字符集的数据被当成了B字符集进行解析,而不是说正确的A字符集转换为B字符集。
例如:如下mysql字符处理机制流程图中,mysql客户端发送的实际上是2个gbk字符(4字节),但character_set_connection
设置了utf8,于是mysql服务器将收到的4字节gbk数据按照utf8解析,得到1个中文字符+1个字节,这时就产生乱码了;

如果character_set_connection 设置为gbk,mysql服务器收到数据后按照gbk解析,得到两个正确的中文,然后再转换为这两个中文对应的utf8编码,这就不会产生乱码。)

【mysql的字符处理机制】

详细的处理机制如下图:



我们模拟一下一条数据从插入到读取的处理流程,看看在整个流程中,字符集是如何辗转腾挪的。
【插入流程】
1. 客户端设定了自己的编码(character_set_client),接收用户的输入;
2. 客户端将用户的输入“转换”成连接的编码(character_set_connection) =====> 第一次转换
3. 客户端将转换后的数据发送给服务器;                               =====> 传输不会导致编码转换
4. 服务器收到客户端的数据,再判断数据列的字符集,进行字符转换       =====> 第二次转换
5. 服务器将数据存储(例如磁盘)                                     =====> 存储不会导致编码转换  

【读取流程】
略去前面的sql语句处理流程,从数据读取开始
1. 服务器从存储(例如磁盘)读取数据                                 =====> 存储不会导致编码转换,因此从存储读取也不需要
2. 服务器判断当前连接返回结果的字符集(character_set_results),
   将读取的数据转换为结果集要求的数据                               =====> 逆向的第一次转换,对应正向的第二次编码转换
3. 服务器将数据发送给客户端                                         =====> 传输不会导致编码转换
4. 客户端收到服务器的数据,根据客户端的字符集(character_set_client)进行编码转换          =====> 逆向第二次转换,对应正向第一次编码转换
5. 客户端显示数据                                                   =====> 你能看到乱码的时候

有了这个流程,我们就很容易定位乱码可能产生的地方,以及产生乱码的字符集配置究竟是哪个了。
理想的情况是整个流程中,所有涉及字符转换的地方都不需要转换,这样就不会产生乱码了。

有了上面的理论分析后,我们再结合一个乱码的抓包实例,加深理解,其中有一些问题,请大家思考一下,看看是否真的理解了。

环境:
+--------------------------+-----------------------------------------------------+
| Variable_name            | Value                                               |
+--------------------------+-----------------------------------------------------+
| character_set_client     | latin1                                              |
| character_set_connection | latin1                                              |
| character_set_database   | utf8                                                |
| character_set_filesystem | binary                                              |
| character_set_results    | latin1                                              |
| character_set_server     | utf8                                                |

测试语句是插入一个中文字符“你”,其utf8编码为"0xE4 0xBD 0xA0",

1. latin1发送包 


思考一下1:为什么客户端和连接都设置了latin1,但最终发送的是正确的utf8编码呢?

2. latin1接收包 


思考一下2:为什么接收到的还是正确的utf8编码?

3. latin1不显示乱码 


思考一下3:为什么latin1显示了正确的utf8字符?

4. utf8接收包 


思考一下4:为什么连接的字符集和数据库的字符集设置成一样了,接收的数据反而不是utf8了?(请与latin1接收数据包对比)

5. utf8显示包


思考一下5:为什么连接的字符集和数据库的字符集设置成一样了,显示反而乱码了? 

怎么样,上面的思考题是否都有答案了,如果没有,相信下面这幅图能够帮助你:

这个抓包案例的字符变化图解:


附:mysql字符编码操作技巧
【查看字符集设置】

mysql> show variables like '%char%';
+--------------------------+-----------------------------------------------------+
| Variable_name      | 说明                        |
+--------------------------+-----------------------------------------------------+
| character_set_client   | 客户端字符集                    |
| character_set_connection | 当前连接字符集                   |
| character_set_database  | 数据库字符集                    |
| character_set_filesystem | 文件系统字符集,不要修改,使用binary即可      |
| character_set_results  | 返回结果集字符集                  |
| character_set_server   | 服务器默认字符集,当数据库、表、列没有设置时,   |
|             |   默认使用此字符集                |
| character_set_system   | 固定为utf8                     |
+--------------------------+-----------------------------------------------------+

【修改字符集设置】
服务器的配置在服务器建立的时候就由DBA设置好了,不推荐后续再改
通过SET NAMES utf8命令同时设置character_set_client/character_set_connection/character_set_results的字符集
建议所有配置都设置成utf8

【问题答案】

思考一下1:为什么客户端和连接都设置了latin1,但最终发送的是正确的utf8编码呢?
客户端设置了latin1,而我的语句是从notepad++中写好的,是utf8格式的;
中文utf8是3个字节,而latin1是按照单个字节解析的,虽然进行了转换,但不会导致二进制内容的变化,但实际上mysql客户端认为我输入了3个latin1字符;
如果客户端设置的编码是2个字节的gbk,这时转换就会发生乱码,utf8的3个字节会被转换为1个gbk字符(可能是乱码,也可能不是乱码)加上一个西欧字符(小于128就是英文,大于128就是其它西欧文)

思考一下2:为什么接收到的还是正确的utf8编码?
这是因为mysql服务器从将数据从“列”的编码(utf8)转换为latin1了,而列存储的数据并不是真正的utf8的中文“你”对应的"0xe4 0xbd 0xa0",
而是后面抓包看到的“c3a4 c2bd c2a0”(6个字节),mysql服务器将utf8的c3a4转换为latin1的0xe4,c2bd转换为0xbd, c2a0转换为0xa0

思考一下3:为什么latin1显示了正确的utf8字符?
因为mysql客户端收到了mysql服务器转换后的"0xe4 0xbd 0xa0",并把这个数据当做latin1的3个字符处理,然后抛给终端(我的是SecureCRT),
SecureCRT又把这三个latin1当做uft8处理,结果中文的“你”就显示出来了。

思考一下4:为什么连接的字符集和数据库的字符集设置成一样了,接收的数据反而不是utf8了?(请与latin1接收数据包对比)
字符集都一样的情况下,整个流程中不需要进行编码转换,直接将存储的“c3a4 c2bd c2a0”返回给客户端

思考一下5:为什么连接的字符集和数据库的字符集设置成一样了,显示反而乱码了?
参考思考4,客户端收到数据后也直接抛给终端显示,终端认为是两个utf8字符,并且找到了对应字符并显示,但我们看不懂,所以知道是乱码了,但这两个字符显示并没有错,如果真正找不到字符,可能会显示问号或者字符集规定的缺省符号。

以上就是关于MySQL乱码问题大集合,希望能够帮助大家解决MySQL乱码问题,更多相关内容请关注PHP中文网(www.php.cn)!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
在MySQL中使用視圖的局限性是什麼?在MySQL中使用視圖的局限性是什麼?May 14, 2025 am 12:10 AM

mysqlviewshavelimitations:1)他們不使用Supportallsqloperations,限制DatamanipulationThroughViewSwithJoinsOrsubqueries.2)他們canimpactperformance,尤其是withcomplexcomplexclexeriesorlargedatasets.3)

確保您的MySQL數據庫:添加用戶並授予特權確保您的MySQL數據庫:添加用戶並授予特權May 14, 2025 am 12:09 AM

porthusermanagementinmysqliscialforenhancingsEcurityAndsingsmenting效率databaseoperation.1)usecReateusertoAddusers,指定connectionsourcewith@'localhost'or@'%'。

哪些因素會影響我可以在MySQL中使用的觸發器數量?哪些因素會影響我可以在MySQL中使用的觸發器數量?May 14, 2025 am 12:08 AM

mysqldoes notimposeahardlimitontriggers,butacticalfactorsdeterminetheireffactective:1)serverConfiguration impactactStriggerGermanagement; 2)複雜的TriggerSincreaseSySystemsystem load; 3)largertablesslowtriggerperfermance; 4)highConconcConcrencerCancancancancanceTigrignecentign; 5); 5)

mysql:存儲斑點安全嗎?mysql:存儲斑點安全嗎?May 14, 2025 am 12:07 AM

Yes,it'ssafetostoreBLOBdatainMySQL,butconsiderthesefactors:1)StorageSpace:BLOBscanconsumesignificantspace,potentiallyincreasingcostsandslowingperformance.2)Performance:LargerrowsizesduetoBLOBsmayslowdownqueries.3)BackupandRecovery:Theseprocessescanbe

mySQL:通過PHP Web界面添加用戶mySQL:通過PHP Web界面添加用戶May 14, 2025 am 12:04 AM

通過PHP網頁界面添加MySQL用戶可以使用MySQLi擴展。步驟如下:1.連接MySQL數據庫,使用MySQLi擴展。 2.創建用戶,使用CREATEUSER語句,並使用PASSWORD()函數加密密碼。 3.防止SQL注入,使用mysqli_real_escape_string()函數處理用戶輸入。 4.為新用戶分配權限,使用GRANT語句。

mysql:blob和其他無-SQL存儲,有什麼區別?mysql:blob和其他無-SQL存儲,有什麼區別?May 13, 2025 am 12:14 AM

mysql'sblobissuitableForStoringBinaryDataWithInareLationalDatabase,而ilenosqloptionslikemongodb,redis和calablesolutionsolutionsolutionsoluntionsoluntionsolundortionsolunsonstructureddata.blobobobissimplobisslowdeperformberbutslowderformandperformancewithlararengedata;

mySQL添加用戶:語法,選項和安全性最佳實踐mySQL添加用戶:語法,選項和安全性最佳實踐May 13, 2025 am 12:12 AM

toaddauserinmysql,使用:createUser'username'@'host'Indessify'password'; there'showtodoitsecurely:1)choosethehostcarecarefullytocon trolaccess.2)setResourcelimitswithoptionslikemax_queries_per_hour.3)usestrong,iniquepasswords.4)Enforcessl/tlsconnectionswith

MySQL:如何避免字符串數據類型常見錯誤?MySQL:如何避免字符串數據類型常見錯誤?May 13, 2025 am 12:09 AM

toAvoidCommonMistakeswithStringDatatatPesInMysQl,CloseStringTypenuances,chosethirtightType,andManageEngencodingAndCollat​​ionsEttingSefectery.1)usecharforfixed lengengtrings,varchar forvariable-varchar forbariaible length,andtext/blobforlargerdataa.2 seterters seterters seterters

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。