news 2026/10/7 23:58:29

Python连接MYSQL数据库的两种方式:pymysql与sqlalchemy实战配置

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python连接MYSQL数据库的两种方式:pymysql与sqlalchemy实战配置

1. 为什么 Python 连 MySQL 总在第一步卡住

Python 连接 MYSQL 数据库这件事,说简单也简单,一行connect()就能通;说麻烦也麻烦,密码里带个@、端口没放行、驱动没装对,报错能让你查一下午。我见过太多项目,业务代码写得飞起,结果卡在pymysql.err.OperationalError上动弹不得。

先把概念理清楚。Python 操作 MySQL,本质上分两条路线:

一条是原生驱动路线,代表就是pymysql。它直接跟 MySQL 服务端说协议,你写 SQL 它执行,返回的是元组列表。优点是轻、透明、可控,适合写脚本、做数据清洗、跑一次性任务。缺点是你要自己管连接、自己拼 SQL、自己处理事务提交,稍微复杂点的场景就容易写出一堆重复代码。

另一条是ORM / 引擎路线,代表是sqlalchemy。它在驱动之上又包了一层,提供连接池、方言适配、to_sql这类高层能力。你既可以拿它当"增强版连接器"用(配合 pandas 读写),也可以上完整 ORM 定义模型。优点是工程化程度高,适合后端服务和数据管道;缺点是抽象层多了,出问题时排查链路更长。

那到底该选哪个?我的经验是:临时脚本、单次查询、学习原理,用 pymysql;长期跑的服务、批量入库、需要连接池,用 sqlalchemy。两者不是替代关系,sqlalchemy 底层照样可以调 pymysql 当驱动,所以你会经常看到它们一起出现。

这篇就按"能直接复制去跑"的标准来写。从依赖安装、连接参数、查询验证,到密码含特殊字符的坑、连接池配置、再到连接失败的排查清单,一步步走完。目标很明确:让你在本地和远程两种环境下,都能把连通性验证跑通,并且知道报错时该看哪里。

适合谁看?后端开发要接数据库的、数据工程要做 ETL 的、以及刚学 Python 想搞明白"连接"到底怎么回事的朋友。不需要你懂 MySQL 内核,但得会基本的 SQL 和命令行操作。

下面正式开始。先装依赖,再分别用两种方式连,最后统一排障。

2. 动手前的准备:依赖安装与 TaoToken 接入配置

在写连接代码之前,有两件事必须先落地:一是 Python 环境里的依赖装齐,二是如果你打算用大模型辅助写 SQL、生成建表语句或者排查报错,可以先把 TaoToken 的接入配好。这一节把这两块都讲清楚。

2.1 依赖安装:pymysql、sqlalchemy、pandas 一个都不能少

打开终端,建议在虚拟环境里操作,避免污染全局包。三条命令搞定:

python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install pymysql sqlalchemy pandas

版本上不用太纠结,pymysql1.x、sqlalchemy2.x 都能跑本文的代码。装完验证一下:

python -c "import pymysql, sqlalchemy, pandas; print(pymysql.__version__, sqlalchemy.__version__, pandas.__version__)"

能打印出版本号就说明环境 OK。这里有个小坑:sqlalchemy2.0 之后 API 有变化,网上很多老教程用的是 1.4 的写法,混着抄容易报ArgumentError。本文代码以 2.x 为准,遇到不兼容我会标注。

2.2 TaoToken 接入:Base URL、API Key、Model ID 三件套

如果你想让模型帮你根据表结构生成查询、把自然语言转成 SQL,或者在你贴报错时快速定位,可以接一个兼容 OpenAI 协议的服务。TaoToken 的接入就三样东西,缺一不可:

  • Base URL:https://taotoken.net/api
  • API Key:在控制台创建,形如sk-xxxx
  • Model ID:按你需要的模型填,比如对话类、代码类各有对应 ID

以 Claude Code 这类编码工具为例,配置通常写在一个 JSON 或环境变量里。下面是一个通用的settings.json片段,路径按你实际工具的约定放(比如~/.claude/settings.json或项目根目录):

{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的Key", "ANTHROPIC_MODEL": "你的ModelID" } }

如果你用的是 Cline、Codex 这类工具,思路一样:Base URL 填https://taotoken.net/api,Key 填你创建的,Model ID 填对应模型。三件套对齐了,工具才能正常发请求。Codex 的auth.json里也是同样的字段结构,把 base_url 和 api_key 对应填进去即可。

注意:Base URL 不要自己加/v1后缀,也不要带多余斜杠,按上面给的写。Key 泄露了要立刻去控制台吊销重建。

配好之后,你可以先在模型对话里让它帮你写一段建表 SQL 或者解释一个报错,验证链路是通的。这一步不是必须的,但对接下来的排错很有帮助——尤其是遇到pymysql.err这类错误时,把完整堆栈贴进去,能省不少搜索时间。

环境准备好了,下面进入正题,先看 pymysql 怎么连。

3. 方式一:pymysql 原生连接与可复制配置

pymysql 是最直白的连接方式。你给它地址、端口、账号、密码、库名,它给你一个 connection 对象,剩下的就是写 SQL。

3.1 基础连接与查询

先看最小可用版本。把下面的参数换成你自己的:

import pymysql import pandas as pd con = pymysql.connect( host="数据库地址", # 本地填 127.0.0.1,远程填公网/内网 IP port=3306, # MySQL 默认 3306 user="用户名", passwd="密码", db="数据库名称", charset="utf8mb4" # 强烈建议 utf8mb4,支持 emoji ) mycursor = con.cursor() print("连接成功") sql = "select * from 数据库表名 where 字段名 = 'xx'" result = pd.read_sql(sql, con=con) print(result)

几个关键点解释一下。charset="utf8mb4"别写成utf8,后者在 MySQL 里是残缺的三字节版本,存 emoji 会报Incorrect string value。pd.read_sql直接吃 connection 对象,返回 DataFrame,比手动 fetchall 再拼列名舒服得多。

3.2 增删改与事务提交

查询不用提交,但增删改必须commit(),否则数据不会真正落库:

sql = "delete from 数据库表名 where 字段名 = 'xx'" mycursor.execute(sql) print("删除数据长度:", mycursor.rowcount) con.commit() # 忘了这行,删除等于没删

mycursor.rowcount返回受影响行数,调试时很有用。这里有个新手常踩的坑:执行完execute不commit,程序退出后连接关闭,改动被回滚,你会以为"代码没生效"。记住:写操作必 commit。

3.3 用上下文管理器避免连接泄漏

手动con.close()容易忘。更稳的写法是用with:

with pymysql.connect( host="127.0.0.1", port=3306, user="root", passwd="你的密码", db="test_db", charset="utf8mb4" ) as con: with con.cursor() as cur: cur.execute("select count(*) from users") print(cur.fetchone())

with块结束会自动关闭游标和连接,异常时也能保证释放。生产脚本建议都这么写。

3.4 参数化查询防注入

千万别用 f-string 拼 SQL,用户输入带个引号就能把你表删了。正确姿势是占位符:

sql = "select * from users where name = %s and age > %s" cur.execute(sql, ("张三", 18))

pymysql用%s占位(不是?),它会帮你转义。这是硬性规范,不是可选项。

pymysql 讲完了,它的边界也很清楚:连接要自己管,复杂查询要自己拼。接下来看 sqlalchemy 怎么把这些事接管过去。

4. 方式二:sqlalchemy 引擎、连接池与 to_sql 实战

sqlalchemy 的核心是create_engine。它返回的不是连接,而是"连接工厂 + 连接池",你每次用的时候它从池里借一个,用完还回去。这对高并发服务是刚需。

4.1 基础引擎创建

import pymysql from sqlalchemy import create_engine pymysql.install_as_MySQLdb() # 让 sqlalchemy 能用 pymysql 当 MySQLdb 的替身 conn = create_engine( "mysql+mysqldb://root:密码@数据库地址:端口号/数据库名称?charset=utf8mb4" )

连接串格式是方言+驱动://用户:密码@主机:端口/库名?参数。这里mysql+mysqldb配合install_as_MySQLdb(),底层实际走的是 pymysql。你也可以直接写mysql+pymysql://,效果一样,还省掉那行 install。

4.2 密码含 @ 等特殊字符怎么办

这是重灾区。密码里如果有@、#、/,直接拼进 URL 会被解析成主机分隔符,连接必然失败。解决办法是用quote_plus转义:

from urllib.parse import quote_plus as urlquote userName = "用户名" password = "@123456" # 含 @ 的密码 dbHost = "数据库地址" dbPort = 3306 dbName = "数据库名称" DB_CONNECT = f"mysql+pymysql://{userName}:{urlquote(password)}@{dbHost}:{dbPort}/{dbName}?charset=utf8mb4" conn = create_engine(DB_CONNECT)

urlquote("@123456")会变成%40123456,URL 解析就不会误判了。这个坑我踩过,当时查了半天才反应过来是密码里的@在作怪。

4.3 连接池参数配置

默认连接池很小,服务一上量就报QueuePool limit overflow。生产环境建议显式配置:

conn = create_engine( DB_CONNECT, max_overflow=50, # 池满后最多再创建 50 个连接 pool_size=50, # 连接池常驻大小 pool_timeout=60, # 池空时最多等 60 秒,超时报错 pool_recycle=3600, # 连接存活 1 小时后回收重建,防 MySQL 主动断连 pool_pre_ping=True, # 借出前先 ping 一下,剔除失效连接 echo=False # True 会打印所有 SQL,调试用 )

pool_recycle和pool_pre_ping是保命参数。MySQL 默认wait_timeout是 8 小时,连接放久了会被服务端单方面掐断,客户端不知道,下次用就报Lost connection。pool_recycle=3600让连接一小时就换新,pool_pre_ping再兜一层底。

4.4 用 to_sql 批量入库

这是 sqlalchemy 最香的地方。DataFrame 直接写库:

data.to_sql( name="数据库表名", con=conn, if_exists="append", # append 追加 / replace 覆盖 / fail 报错 index=False # 不把 DataFrame 索引写成一列 )

if_exists="append"是增量入库,配合定时任务做数据同步非常顺手。注意index=False,否则会多出一列index,很多人第一次用都中招。

4.5 执行原生 SQL

需要复杂查询时,用text()包一下:

from sqlalchemy import text with conn.connect() as connection: result = connection.execute(text("select * from users where age > :age"), {"age": 18}) for row in result: print(row)

命名参数用:age,比%s更清晰。conn.connect()从池里借连接,with结束自动归还。

两种方式都讲完了。接下来验证一下到底通没通。

5. 验证请求与成功结果:从连接测试到查询回显

代码写完不代表能跑通。这一节给你一套标准验证流程,从最轻量的连通性测试,到真实查询回显,逐层确认。

5.1 最小连通性测试

先别急着查业务表,用一条select 1确认链路:

import pymysql try: con = pymysql.connect( host="127.0.0.1", port=3306, user="root", passwd="你的密码", db="test_db", charset="utf8mb4", connect_timeout=5 ) with con.cursor() as cur: cur.execute("select 1") print("连通性 OK:", cur.fetchone()) con.close() except Exception as e: print("连接失败:", repr(e))

成功会打印连通性 OK: (1,)。connect_timeout=5很重要,否则网络不通时默认会卡很久。这一步过了,说明地址、端口、账号、密码、库名全对。

5.2 sqlalchemy 侧验证

from sqlalchemy import create_engine, text engine = create_engine("mysql+pymysql://root:密码@127.0.0.1:3306/test_db?charset=utf8mb4") with engine.connect() as conn: version = conn.execute(text("select version()")).scalar() print("MySQL 版本:", version)

能拿到版本号,说明引擎、驱动、连接池整条链路都正常。

5.3 真实查询回显

连通性过了,再查真实表:

import pandas as pd import pymysql con = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="密码", db="test_db", charset="utf8mb4") df = pd.read_sql("select * from users limit 5", con=con) print(df.head()) print("行数:", len(df)) con.close()

预期输出是带列名的表格,行数跟你limit一致。如果列名乱码,回去检查charset;如果报Table doesn't exist,确认库名和表名拼写。

5.4 写入验证

读通了,再验证写:

with con.cursor() as cur: cur.execute("insert into users(name, age) values(%s, %s)", ("测试用户", 20)) con.commit() print("插入行数:", cur.rowcount)

然后重新查一次,能看到"测试用户"就说明读写都通了。记得测完把测试数据删掉,别污染业务表。

验证流程走完,如果哪一步报错,直接进下一节的排查清单。

6. 连接失败排查清单:401、proxy、choices 与 OAuth 报错对照

报错不可怕,可怕的是不知道看哪。这一节按真实错误信息分类,给你对照表。

6.1 认证类:401 与 Access denied

pymysql.err.OperationalError: (1045, "Access denied for user 'root'@'x.x.x.x' (using password: YES)")

这是账号密码错,或者该用户没有从你这个 IP 连接的权限。排查顺序:密码是否含特殊字符没转义、用户是否授权了%或你的具体 IP、MySQL 8 的caching_sha2_password认证插件是否被老驱动支持(升级 pymysql 即可)。

如果你在调模型接口时看到401 Unauthorized,那是 API Key 的问题,跟数据库无关。检查 Key 是否填对、是否过期、Base URL 是否写成https://taotoken.net/api。Key 和 URL 不匹配也会 401。

6.2 网络类:local proxy failed 与超时

pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on 'x.x.x.x' (timed out)")

网络不通。检查:MySQL 是否在跑、端口是否放行(云服务器安全组!)、bind-address是否只绑了127.0.0.1导致外部连不上。本地连远程时,先telnet 主机 3306确认端口可达。

如果你在工具里看到local proxy failed或类似代理错误,通常是工具自身的网络配置问题,检查它的 base_url 是否可达,别把代理地址填错。

6.3 驱动与解析类:reading choices 与 OAuth

sqlalchemy.exc.ArgumentError: Could not parse SQLAlchemy URL

连接串格式错。常见于密码含@没转义、mysql+mysqldb写成了mysql+mysql、或者多了空格。用urlquote处理密码,格式严格按方言+驱动://用户:密码@主机:端口/库名来。

reading choices这类报错多见于模型接口返回体解析异常,通常是返回的不是预期 JSON(比如返回了 HTML 错误页)。检查 Base URL 是否被重定向、Key 是否有权限访问该模型。

OAuth相关报错出现在用 OAuth 方式登录的工具里,比如 token 过期或 scope 不足。重新走一遍授权流程,或者改用 API Key 方式接入。

6.4 连接池类:QueuePool limit overflow

sqlalchemy.exc.TimeoutError: QueuePool limit of size 5 overflow 10 reached

连接池不够用。调大pool_size和max_overflow,同时检查代码里有没有忘记关闭连接导致泄漏。用with语句能规避大部分泄漏。

6.5 字符集类:Incorrect string value

pymysql.err.DataError: (1366, "Incorrect string value")

字符集不匹配。连接用utf8mb4,建表也用utf8mb4,两边对齐。老库如果是utf8,存 emoji 必报这个错。

排查时记住一个原则:先看完整堆栈,定位是连接层、认证层还是 SQL 层。连接层看网络和参数,认证层看账号和 Key,SQL 层看语句和字符集。把堆栈贴给模型对话,通常几秒就能给出方向。

7. 收尾:把两种方式用在对的地方

写到这里,pymysql 和 sqlalchemy 两条路都跑通了。最后说点实在的选型经验,不搞总结套话。

临时脚本、数据清洗、一次性导出,我基本都用 pymysql,代码短、依赖少、出问题一眼看到底。长期跑的服务、定时同步、批量入库,一律上 sqlalchemy,连接池和to_sql省下的维护成本远超学习成本。两者不冲突,sqlalchemy 底层照样用 pymysql 当驱动,所以你的 pymysql 知识不会浪费。

几个我反复用到的实用技巧:连接串里的密码永远用urlquote转义;pool_pre_ping=True和pool_recycle=3600是生产标配;写操作别忘commit;charset统一utf8mb4。这几条能帮你避开八成的连接类故障。

真遇到报错,别急着搜。先把完整堆栈读一遍,判断是连接、认证还是 SQL 层,再对照第 6 节的清单定位。需要生成 SQL 或解释报错时,把表结构和错误信息一起贴给模型,比只贴一行错误高效得多。

代码能跑通只是开始,把连接管理好、把异常兜住,才是能上生产的代码。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 23:49:53

如何快速上手Wardrobe:10分钟搭建个人AI衣橱的5步完整教程

如何快速上手Wardrobe:10分钟搭建个人AI衣橱的5步完整教程 【免费下载链接】wardrobe Your clothes, extracted and organized with gpt-image. 项目地址: https://gitcode.com/gh_mirrors/wardro/wardrobe Wardrobe 是一个本地优先(Local-first&…

作者头像 李华
网站建设 2026/10/7 23:46:58

小智AI接入MCP:从零实现语音控制电脑音量

小智AI这个项目,最近在智能家居和桌面自动化圈子里讨论度确实高。用语音让AI把电脑音量调高调低,听起来是个小事,但真要把“人说话—AI理解—调用工具—设备执行”这条链路完整跑通,中间涉及的环节并不少。我在自己的Windows开发机…

作者头像 李华
网站建设 2026/10/7 23:44:30

Spring AI在阿里云落地实战:React Agent工程化四步法

1. 这不是“第九掌”,而是Spring AI在阿里云生态落地的实战切口 “降SpringAI阿里第9掌-或跃在渊-ReactAgent”——这个标题乍看像武侠秘籍,实则是当前Java开发者在阿里云环境里推进AI Agent落地时,一个极具代表性的技术切口。它不讲玄学&…

作者头像 李华