简介一份Python3连接并操作MySQL数据库的实战讲解资源面向正在学习PyMySQL库的初中级Python开发者也适合需要在多数据库环境中快速搭建连接模块的工程人员。内容基于Python3.7与PyMySQL0.9.3围绕封装后的数据库连接类展开覆盖连接配置、游标使用、SQL执行、事务提交与异常回滚等关键环节并分别演示查询、增、删、改四类操作。资源为单个PDF文档体积仅约50KB可在手机或电脑上随时查阅。PDF内附完整类定义及do_one、select两个方法的逐段解析包括连接参数dict的字段说明与返回结果结构便于读者直接复制改造迅速应用到实际项目中。该资源已有2395人学习浏览适合想要通过一份精简文档快速掌握PythonMySQL核心操作的学习者。1. Python3 连接 MySQL先选对驱动再动手Python3 连接 MySQL 做增删改查是爬虫落库、后台接口、数据清洗脚本里绕不开的基础动作。很多人拿到需求就装个 PyMySQL 写 connect()但连接参数、字符集、事务边界没想清楚等数据写进去才发现乱码、丢更新或者连接被服务端掐断。这篇文章按「选驱动 → 建连接 → 写操作 → 管事务 → 排错」的顺序展开从最小可运行代码讲到连接池和健康检查适合刚接触 Python3 数据库编程的新手也适合从其他语言转过来、想快速对齐细节的工程师。读完你应该能独立写出带参数化 SQL、事务和异常处理的存取代码。2. Python3 与 MySQL 连接环境搭建驱动选型、安装与最小连接动手前先把驱动定下来。Python3 下连 MySQL 不像 JDBC 只有一条官方路径社区和官方给了好几个选择选错会在编译和认证阶段浪费不少时间。2.1 PyMySQL 与 mysql-connector-python两个常用驱动怎么选驱动安装方式是否纯 Python典型场景MySQLdb / mysqlclientpip install mysqlclient否依赖 C 编译遗留项目迁移、性能敏感PyMySQLpip install pymysql是绝大多数 Python3 新项目mysql-connector-pythonpip install mysql-connector-python是需要 Oracle 官方支持MySQLdb 是 Python2 时代的主力Python3 下对应 mysqlclient但它依赖 C 编译在 Windows 上装 wheels 偶尔要补运行库为一个脚本折腾编译不值得。PyMySQL 是纯 Python 实现pip 装上直接能用支持 MySQL 5.7 到 8.0 的 caching_sha2_password 认证社区资料最多出问题一搜就有答案。mysql-connector-python 是官方出品API 和 PyMySQL 高度相似但包体积大速度无明显优势除非项目规定了官方依赖我一般默认选 PyMySQL。补一个兼容技巧老项目代码里有 import MySQLdb 的可以在入口处用 pymysql.install_as_MySQLdb() 做替换避免改全量业务代码。注意这个方法只保证基础 API 兼容别指望底层 C 类型也完全一致。2.2 pip 安装并验证Python3 环境常见坑# 建虚拟环境避免污染系统 PythonPEP 668 环境下 pip 会拒绝直接装 python3 -m venv .venv source .venv/bin/activate pip install pymysql # 验证驱动可导入 python3 -c import pymysql; print(pymysql.__version__)前三行先建虚拟环境这是系统 Python 普遍启用 externally-managed-environment 后最常见的坑不建 venv 直接 pip install 会报错。后两行是验证能打印版本号说明驱动装好了如果 import 报错先确认当前 shell 是否真的在虚拟环境里再看 pip list。后面再用 pycharm 或 vscode 配好的 python 环境加载同一个虚拟环境调试时可以直接在 IDE 里断点观察游标内容。连接前还要确认 MySQL 服务本身在跑。装好 MySQL 8.0 后初始密码随安装方式不同Windows 安装器会让你设置Linux 仓库包则常写在 /var/log/mysql/error.log 里。我一般先用 mysql workbench 建一条连接验证账号能登录再回过来排查 Python 侧这样能把问题快速切成「MySQL 没起来」还是「Python 连不上」两段。2.3 第一条 Python3 连接 MySQL 的代码参数逐项说明import pymysql conn pymysql.connect( host127.0.0.1, # MySQL 所在主机跨机写内网 IP port3306, # 默认端口改过要同步 userroot, passwordyour_password, charsetutf8mb4, # 必须写避免中文乱码 connect_timeout3, # 秒超时快速失败 ) with conn.cursor() as cur: cur.execute(SELECT VERSION()) print(cur.fetchone()) conn.close()connect() 返回的是连接对象真正的 SQL 执行要交给游标 cursor。connect_timeout 很多人不写默认值在 MySQL 不可达时会让程序卡很久调试期建议显式设 3 秒。charset 用 utf8mb4 而不是 utf8因为 MySQL 的 utf8 实际只存 3 字节遇到 emoji 或生僻字会直接报错。host 写 127.0.0.1 而不是 localhost两者在账号授权表里可能对应不同记录本地开发没问题跨机联调时经常遇到 1045 权限错误属正常现象。提示with conn.cursor() 只关游标不关连接。连接还是要手动 close()或放进 finally 里保证释放。3. Python3 操作 MySQL 增删改查游标、参数化 SQL 与结果读取连接建好后真正的日常工作是增删改查。这一章从游标机制讲起给出一套可以直接抄的 CRUD 代码再讲清结果集怎么读才不容易踩内存和状态同步的坑。3.1 游标与连接的关系为什么 Python3 操作 MySQL 要先建 cursorMySQL 连接本质是一条 TCP 长连接把 SQL 发给服务端、再收回结果集。游标可以理解成挂在连接上的「结果集管道」同一个连接可以反复创建多个游标但同一时刻未读尽的结果集和下一次 execute 会互相干扰。默认的 Cursor 返回元组每一行是 (id, name, age)适合代码里列顺序固定的场景需要按列名取值时改成 pymysql.cursors.DictCursor返回字典可读性高很多。一个常见误区是认为 with conn.cursor() 会把连接也关掉。实际上它只调 cursor.close()把该游标未读完的结果清理掉连接本身还活着。理解这点写多批次操作时就不会因为「游标已关闭」而反复新建连接。3.2 增删改查的最小代码参数化 SQL 的四个例子import pymysql conn pymysql.connect( host127.0.0.1, userroot, passwordyour_password, databasetest_db, charsetutf8mb4, ) try: with conn.cursor() as cur: cur.execute( CREATE TABLE IF NOT EXISTS user_info ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL, age INT NOT NULL DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP) ) # C插入%s 占位值由第二个参数传入 cur.execute( INSERT INTO user_info (name, age) VALUES (%s, %s), (ali, 28), ) print(新插入 id:, cur.lastrowid) # U更新条件也走参数绝不拼字符串 cur.execute( UPDATE user_info SET age %s WHERE name %s, (29, ali), ) print(受影响行数:, cur.rowcount) # R查询带过滤和排序 cur.execute( SELECT id, name, age FROM user_info WHERE age %s ORDER BY age DESC, (20,), ) for row in cur.fetchall(): print(row) # D删除 cur.execute(DELETE FROM user_info WHERE name %s, (ali,)) conn.commit() finally: conn.close()四个操作共用同一个连接和同一个游标commit 放在所有写操作之后保证一组操作要么全部生效、要么全部回滚。lastrowid 是刚插入的自增主键批量导入后要拿 id 关联外键时很有用rowcount 表示 UPDATE/DELETE 实际影响的行数不是「匹配到」的行数返回 0 说明该行已不存在。PyMySQL 的占位符是 %s不管字段是字符串还是数字都写 %s由驱动负责类型转换。严禁用 f-string 拼 SQL比如fSELECT * FROM t WHERE name{name}这等于把 SQL 注入漏洞直接暴露给调用方参数化之后特殊字符会被转义注入和引号报错同时消失。调用存储过程也走同一套 execute写成cur.execute(CALL proc(%s), (arg,))参数化规则不变。3.3 fetchone、fetchmany、fetchall查询结果怎么读方法返回适用场景fetchone()单行或 None查单条记录、循环取数fetchmany(size)最多 size 行分批处理大结果集fetchall()全部行结果集小一次载入内存三个方法都在消费同一个结果集。fetchall 一次性把所有行读进内存几千行没问题几十万行会把 Python 进程内存顶爆。fetchmany(size) 适合边读边处理配合生成器写成分批任务。还有一类流式读取场景PyMySQL 提供 SSCursor它不在客户端缓存结果而是边读边从网络取适合导出大表副作用是读取期间该连接不能再执行其他 SQL否则报 Commands out of sync这点很容易踩。另外要提醒同一个连接上下一次 execute() 会丢掉上一次未读完的结果。如果你 fetchall 后没取完就想再查别的先确认结果被消费干净否则第二次查询拿到空结果或直接报错。习惯上一条结果集处理完再开下一条两条查询交替用不同游标更安全。4. 事务、连接池与异常处理Python3 操作 MySQL 的进阶细节基础 CRUD 跑通后真正拉开差距的是事务边界、连接复用和异常定位。这三件事决定代码在并发和故障场景下是稳定还是频繁出暗病。4.1 commit 与 rollbackPython3 操作 MySQL 的事务边界PyMySQL 默认 autocommitFalse意味着每次 UPDATE/INSERT/DELETE 虽然执行成功但只在当前事务里可见必须 commit() 才算落盘。很多人写脚本没有 commit程序退出后数据神秘消失十有八九是这个原因。反过来查询 SELECT 不需要 commit它不改变数据。try: with conn.cursor() as cur: cur.execute(UPDATE user_info SET age age 1 WHERE name %s, (ali,)) cur.execute(INSERT INTO user_log (name, action) VALUES (%s, %s), (ali, update_age)) conn.commit() except Exception: conn.rollback() raise把两个写操作放进同一个事务是正确的第二个失败时 rollback 会把第一个也撤掉避免「改了数据但没记日志」这类半截状态。注意 rollback 之后要重新 raise否则调用方拿到的连接处于可用状态但事务上下文已经没了继续往下走会产生幻觉数据。还有一点经常被忽略MySQL 的 DDLCREATE/ALTER/DROP隐式提交不能回滚所以建表语句要放在事务外面。4.2 用 DBUtils 连接池复用 Python3 的 MySQL 连接短脚本里一次连接一次关闭没毛病但 Web 接口每请求都建连TCP 握手加认证的耗时会被放大。常见做法是用 DBUtils 的 PooledDB 维护一批连接用完归还而不是关闭。注意新版 DBUtils 的导入路径已经变成 dbutils.pooled_db老资料里的 from DBUtils.PooledDB 在新版本会直接 ImportError。pip install DBUtilsfrom dbutils.pooled_db import PooledDB import pymysql pool PooledDB( creatorpymysql, maxconnections10, # 连接池最大容量 mincached2, # 空闲时最少保留 maxcached5, # 空闲时最多保留 blockingTrue, # 池满时阻塞等待而不是报错 ping1, # 取连接时探活防止拿到已被服务端断开的连接 host127.0.0.1, userroot, passwordyour_password, databasetest_db, charsetutf8mb4, ) conn pool.connection() with conn.cursor() as cur: cur.execute(SELECT COUNT(*) FROM user_info) print(cur.fetchone()) conn.close() # 归还连接不是真关闭maxconnections 是上限超过后新请求按 blocking 决定是等待还是抛异常ping1 表示每次取连接时先做轻量探活配合 MySQL 的 wait_timeout 默认 8 小时能避免拿到早已被服务端回收的连接。pool.connection() 拿到的对象用法和普通连接一致但 conn.close() 语义变成归还归还后又调底层接口真的断开连接池就白搭了。4.3 异常类型与排错顺序异常典型错误码含义pymysql.err.OperationalError2002 / 1045 / 2013连不上、认证失败、连接中途断开pymysql.err.IntegrityError1062 / 1451唯一键冲突、外键约束失败pymysql.err.ProgrammingError1064 / 1054SQL 语法错、列不存在pymysql.err.DataError1265 / 1366数据超出字段范围或字符集不符排错固定按四层走第一MySQL 本身活着吗用 workbench 或 mysql 命令行试连第二账号授权对不对跨机连接要确认 user 是 user% 而不是只允许 localhost第三连接参数对不对端口、密码、database 是否存在第四SQL 本身有没有问题把报错里的 SQL 片段复制到命令行执行一遍。Python 侧所有数据库异常都挂在 Exception 下面但不建议裸 except Exception 吞掉至少把错误码打出来。from pymysql.err import OperationalError, IntegrityError try: conn pymysql.connect(host127.0.0.1, userroot, passwordx, databasetest_db) except OperationalError as e: # e.args[0] 是错误码e.args[1] 是可读信息 print(f{e.args[0]}: {e.args[1]})pymysql 的异常 args 第一个元素是 MySQL 错误码第二个是消息文本写日志时两个都要留。2002 表示 socket 连不上先查服务端口1045 是密码或授权问题查账号权限2013 Lost connection 多半是 SQL 太大或执行超过 net_read_timeout要调服务端参数而不是改 Python。5. 用最小健康检查脚本验证 Python3 连 MySQL 的每一层这章给一个能直接落地的做法把连接检查封装成自检函数部署前和排障时各跑一次把「服务没起」「授权不对」「SQL 写错」三层问题一次性曝出来。import time import pymysql def check_mysql(host127.0.0.1, userroot, password, databasetest_db, port3306): start time.time() try: conn pymysql.connect( hosthost, portport, useruser, passwordpassword, databasedatabase, charsetutf8mb4, connect_timeout3, ) conn.ping(reconnectTrue) with conn.cursor() as cur: cur.execute(SELECT 1) assert cur.fetchone()[0] 1 cur.execute(SHOW VARIABLES LIKE collation_server) print(collation:, cur.fetchone()[1]) print(fok, {time.time() - start:.3f}s) conn.close() return True except Exception as e: print(failed:, type(e).__name__, e) return False check_mysql()三段检查各有用途connect_timeout3 保证 MySQL 不可达时 3 秒内报错而不是挂起conn.ping(reconnectTrue) 会在断链时尝试重连一次验证连接没有被服务端回收SELECT 1 是数据库界通用的连通性探针比查版本号更轻。最后打印 collation_server顺带确认服务端字符集是 utf8mb4 系避免客户端写了 utf8mb4、服务端却是 latin1导致存进库里的中文变形。自检通过后再处理两个高频坑一是执行大批量写入报 1153 或 2006那是 max_allowed_packet 太小改用 executemany 分批并把单批控制在几千行以内二是程序空闲一段时间后第一次查询特别慢那是 wait_timeout 断链后重连的正常代价连接池里把 ping 打开就能缓解。把这些检查写进部署脚本Python3 连 MySQL 这层基本不会再出暗故障。本文还有配套的精品资源点击获取