Python连接MySQL查询结果出现乱码怎么办?charset参数配置详解

来源:站长联盟作者:深圳网站建设头衔:草根站长
导读:本期聚焦于深圳网站建设创作的《Python连接MySQL查询结果出现乱码怎么办?charset参数配置详解》,敬请观看详情。Python从MySQL中查询出来的数据全是问号或者一串看不懂的符号,这个问题困扰过不少写脚本的朋友。乱码的根源通常不在数据库本身,而在连接环节缺少正确的字符集设置。本文围绕pymysql和mysql-connector两个常用库,详细讲解charset参数的正确写法、连接前的排查步骤,以及数据库、表、连接三层编码不一致时该怎么办。同时会分析utf8与utf8mb4的区别,给出建立连接时的完整参数示例,并附上乱码排查的检查清单,帮助你一次性解决中文数据显示异常的问题。

用Python从MySQL里取数据,明明数据库客户端里看是正常的中文,一到脚本里打印出来就变成了一串问号或者类似"杩欐槸涓枃"这样的乱码,这是很多人第一次用Python操作MySQL时都会遇到的情况。问题的核心往往出在连接层:数据库本身的数据是完好的,但连接通道没有指定正确的字符集,导致客户端和服务器之间用了不同的编码方式来解释同一串字节。本文会从原理到实操,把charset参数的配置方法和完整的排查思路讲清楚。

Python连接MySQL查询结果出现乱码怎么办?charset参数配置详解

乱码产生的根本原因是什么

要理解乱码,先要明白一个前提:数据在数据库中存储的是字节,在屏幕上显示的是字符,字节到字符的转换依赖字符集。MySQL服务端有服务器的默认字符集,每个数据库、每张表、甚至每个字段都可以有自己的字符集,而客户端连接进来时,还会带一个连接字符集(character_set_client、character_set_connection、character_set_results这三者合称连接字符集)。

查询中文出现乱码,绝大多数情况是这样一个过程:数据库里的数据以utf8或utf8mb4存储,Python这边通过连接读取时,如果连接字符集被设置成了latin1(这是很多老版本MySQL的默认值),服务器会把utf8存储的数据"翻译"成latin1编码的字节再发给客户端,Python拿到这批字节后按错误的方式解码,显示出来自然就是乱码。反过来,写入数据时如果连接字符集和表字符集不一致,也会造成存进去就是坏的。

可以用下面的SQL在MySQL命令行里确认当前连接的字符集状态:

-- 查看连接相关的三个字符集变量
SHOW VARIABLES LIKE 'character_set_%';
-- 重点看这三个:
-- character_set_client  客户端发送语句使用的字符集
-- character_set_connection 连接层使用的字符集
-- character_set_results  查询结果返回给客户端的字符集

-- 查看具体表的字符集
SHOW CREATE TABLE your_table;

如果发现character_set_results是latin1而表是utf8,乱码的原因就基本锁定了。解决方向很明确:让连接字符集与数据存储字符集保持一致。

pymysql中charset参数的正确写法

pymysql是目前Python生态里最常用的MySQL驱动之一,它在建立连接时支持一个charset参数,专门用来设置连接字符集。这个参数的值必须是MySQL认识的名字,比如utf8、utf8mb4、gbk等,注意要小写,写成utf-8是会报错的,这一点和Python自身的编码名称写法不一样,是新手常踩的坑。

下面是一个标准的连接写法:

import pymysql

# 建立连接时显式指定charset
conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='your_password',
    database='test_db',
    charset='utf8mb4',   # 注意是utf8mb4,不是utf-8
    cursorclass=pymysql.cursors.DictCursor
)

try:
    with conn.cursor() as cursor:
        cursor.execute("SELECT name FROM users WHERE id = %s", (1,))
        result = cursor.fetchone()
        print(result['name'])  # 正常输出中文
finally:
    conn.close()

charset参数设置之后,pymysql会在握手阶段执行SET NAMES操作,把character_set_client、character_set_connection、character_set_results一次性都设置成指定值,等于替你完成了一次编码声明。如果不想改代码,也可以在拿到连接后手动执行SET NAMES utf8mb4,效果一样,但显式写在connect参数里更清晰,不容易遗漏。

另外提一句mysql-connector-python这个官方驱动的写法,它的参数同样叫charset,用法几乎一致:

import mysql.connector

conn = mysql.connector.connect(
    host='127.0.0.1',
    user='root',
    password='your_password',
    database='test_db',
    charset='utf8mb4'
)

如果用的是SQLAlchemy这类ORM框架,charset要写进连接字符串里,例如mysql+pymysql://user:password@127.0.0.1:3306/test_db?charset=utf8mb4,漏掉这个query参数时乱码问题照样会出现,因为SQLAlchemy底层还是调pymysql建连接。

utf8和utf8mb4怎么选

很多人配置charset时纠结写utf8还是utf8mb4。这里需要澄清一个容易混淆的概念:MySQL里的utf8并不是真正完整的UTF-8,它最多只支持3个字节的字符,而标准的UTF-8最长4个字节。像emoji表情、一些生僻汉字、特殊符号,都需要4个字节才能表示。

如果在连接和建表时都用了utf8,插入一个emoji时可能会直接报错,或者被截断成问号。utf8mb4才是MySQL中真正意义上的UTF-8,MySQL 8.0开始默认字符集已经改成了utf8mb4,所以新项目直接统一使用utf8mb4是最稳妥的做法。

统一编码还涉及数据库和表的层面。如果已有的表是utf8想转成utf8mb4,可以执行转换语句,但要注意转换前备份数据,并确认字段长度,因为同一字符占用的字节数可能变化:

-- 修改数据库默认字符集
ALTER DATABASE test_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 修改表的字符集
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

配置的原则就一句话:库、表、连接三层字符集保持一致,全部统一到utf8mb4,乱码基本就没有生存空间了。

配置正确还是乱码的排查清单

如果charset参数已经写了utf8mb4,查询结果仍然是乱码,说明问题在别的环节,可以按下面的清单逐项排查。

第一,确认数据本身是不是好的。用MySQL命令行客户端或者Navicat、DBeaver等图形工具查看同一条记录,如果工具里显示也是乱码,说明数据在写入阶段就坏了,属于历史遗留问题,需要修复数据本身,单纯改连接参数救不回来。这种情况下可以先尝试把错误编码的数据读出来重新编码,比如以latin1读出utf8存储的内容,再用Python做一次先encode再decode的转换修复。

第二,检查终端的输出编码。Windows下cmd默认是GBK编码,就算Python内部字符串正确,print到cmd窗口也可能显示异常。可以执行chcp 65001把控制台切成UTF-8,或者先写到一个UTF-8编码的文件里确认内容是否正确,别让显示环境的锅背到MySQL头上。

第三,检查Python源文件编码和读取方式。如果代码里硬编码了中文字符串参与查询,源文件应保存为UTF-8,Python 3默认如此一般没问题。如果是从文件读取数据再入库,open函数要显式指定encoding='utf-8',否则Windows下会按GBK解码,写入的数据就是坏的:

# 读取文件时显式指定编码,避免依赖系统默认值
with open('data.txt', 'r', encoding='utf-8') as f:
    lines = f.readlines()

# 修复历史脏数据的一种思路:按错误编码还原再正确解码
raw = '杩欐槸涓枃'  # 乱码字符串
try:
    fixed = raw.encode('latin1').decode('utf-8')
    print(fixed)
except (UnicodeEncodeError, UnicodeDecodeError):
    print('编码链路对不上,需确认原始编码')

第四,如果中间还隔着代理、连接池或者读写分离组件,注意有些连接池在复用连接时会重置字符集设置,必要时在获取连接后重新执行一次SET NAMES,确保每一次操作都在正确的编码环境下进行。

总结一下:Python连接MySQL出现乱码,第一反应应该是检查charset参数是否显式设置为utf8mb4,然后核对库、表、连接三层的字符集是否一致,最后再排查终端显示和数据写入环节。把这三层都统一之后,中文和emoji就能在整条链路上畅通无阻了。

Python MySQL乱码charset编码配置pymysql修改时间:2026-09-05 08:14:34

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260905/50782.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。