一、问题现象与本质分析
当开发者使用pymysql.connect()建立数据库连接后,执行cursor.query()或cursor.execute()方法时,返回结果中经常出现类似æ–‡å—å˜åœ¨的乱码。这种现象的本质是字符集不匹配的三层问题:
- 客户端编码:Python环境的默认编码(通常UTF-8)
- 传输层编码:MySQL协议使用的编码(默认可能为latin1)
- 服务端编码:MySQL服务器配置的character_set_server
二、5种解决方案对比
1. 连接时显式指定字符集
conn = pymysql.connect(
host='localhost',
user='root',
password='123456',
database='test',
charset='utf8mb4', # 关键参数
cursorclass=pymysql.cursors.DictCursor
)
2. 运行时动态设置编码
在已建立的连接上执行SQL命令:
cursor.execute("SET NAMES utf8mb4")
3. 数据库层面永久配置
修改MySQL配置文件my.cnf:
[client]
default-character-set=utf8mb4
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
4. 结果集后处理解码
对获取的结果进行二次编码转换:
result = cursor.fetchall()
decoded_result = [dict((k, v.encode('latin1').decode('utf8'))
for k, v in row.items())
for row in result]
5. 使用连接池配置
在使用DBUtils等连接池时的配置示例:
pool = PooledDB(
creator=pymysql,
charset='utf8mb4',
**other_params
)
三、深入原理:MySQL字符集体系
MySQL的字符集处理涉及四个关键参数:
| 参数名 | 默认值 | 影响范围 |
|---|---|---|
| character_set_client | latin1 | 客户端发送的SQL语句 |
| character_set_connection | latin1 | 服务器解析SQL时的转换 |
| character_set_results | latin1 | 返回结果的编码 |
| character_set_database | 继承server设置 | 新建表的默认编码 |
四、最佳实践建议
- 始终使用utf8mb4替代旧的utf8(支持完整的Unicode包括emoji)
- 在建立连接时显式声明charset参数
- 对已有数据库使用
ALTER DATABASE dbname CHARACTER SET utf8mb4转换 - 检查Python文件头部是否包含
# -*- coding: utf-8 -*-声明 - 使用
SHOW VARIABLES LIKE 'character_set%'诊断当前设置