pymysql连接mysql必须显式指定host='127.0.0.1'、port=3306、charset='utf8mb4',禁用autocommit并手动commit;否则数据不写入、中文乱码或连接失败。

PyMySQL 连接 MySQL 必须显式指定 host='127.0.0.1'、port=3306、charset='utf8mb4',禁用 autocommit,且所有写操作后必须调用 conn.commit() —— 否则数据不会真正写入。
连接失败时先检查 host 和 charset 而不是密码
报 Can't connect to MySQL server 或 Access denied for user,大概率不是密码错了。Docker/WSL 中 localhost 会尝试走 Unix socket,而 PyMySQL 默认走 TCP,所以务必写死 host='127.0.0.1';charset 若漏设或错写成 'utf8'(缺 mb4),会导致中文存成问号或抛 UnicodeEncodeError。
- 用命令行验证账号:运行
mysql -h 127.0.0.1 -P 3306 -u root -p看能否登录 - 检查 MySQL 是否监听:执行
netstat -an | grep 3306,确认有LISTEN状态 - 字符集必须是
'utf8mb4',不是'utf8'(MySQL 的utf8实际只支持 3 字节 Unicode)
execute() 必须用 %s 占位符,不能拼字符串
cursor.execute("INSERT INTO t (name) VALUES ('" + name + "') 是危险操作,用户输入 ' OR 1=1 -- 就能绕过条件甚至删库。PyMySQL 的 %s 是协议级占位符,和 Python 字符串格式化无关,不支持 {} 或 f""。
- 安全写法:
cursor.execute("SELECT * FROM users WHERE name = %s", ("张三",))—— 参数必须是元组或字典 - 批量插入用
executemany():cursor.executemany("INSERT INTO t(a,b) VALUES (%s,%s)", [("x",1), ("y",2)]) - 字段名、表名不能参数化,需由可信来源控制(如白名单校验),否则仍可能被注入
增删改后不 commit() 数据就丢了
INSERT/UPDATE/DELETE 执行完只是“暂存在事务中”,不 conn.commit() 就像没执行。而 SELECT 不需要 commit,但必须用 fetchone() 或 fetchall() 拿结果,否则游标里什么也看不到。
- 推荐初始化时设
autocommit=False(默认值),自己显式控制事务边界 - 出错时记得
conn.rollback(),避免脏数据残留 - 用
with语句无法自动 commit,它只保证close(),事务仍需手动处理
查出来的字段名怎么拿到?用 DictCursor 或 description
默认游标返回的是 tuple,你得靠位置索引取值,比如 row[0] 是 id,row[1] 是 name —— 一旦 SQL 字段顺序变,代码就崩。想按名字取值,有两个办法:
- 创建游标时指定
cursor=pymysql.cursors.DictCursor,结果就是字典:row["name"] - 保持默认游标,用
cursor.description获取字段元信息:[d[0] for d in cursor.description]返回字段名列表 - 注意
DictCursor有轻微性能开销,高吞吐场景慎用
最容易被忽略的是:事务提交不是“可选项”,而是写操作的强制步骤;还有 utf8mb4 和 127.0.0.1 这两个硬性配置,少一个都可能让程序在本地跑通、上线就跪。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











