
1. 为什么你写的 Python 查 MySQL 总是「拿不到想要的数据」很多人第一次用 Python 连 MySQL代码大概长这样pymysql.connect(...)拿到连接然后cursor.execute(select * from student)接着print(cursor.fetchall())屏幕上哗啦一下刷出一堆元组任务就算完成了。可一旦需求稍微变一点比如「只打印女生」「把姓名拼成一句话」「按性别分组统计」立刻就卡住了——因为数据已经变成一坨打印输出你没法再对它做二次加工。问题的根子在于execute()执行完 SQL 之后结果集并不是直接怼到屏幕上的它被暂存在数据库服务端或客户端缓冲区里等你通过一个叫**游标cursor**的接口去取。游标就像一根「读取指针」你取一条它往前挪一格你取全部它一次性把剩下的都给你。理解了游标你才能把「查询」和「处理」拆成两步先拿到干净的数据结构再用 Python 的循环、判断、格式化去随意折腾。这篇就围绕python、mysql、cursor这条主线把连接建立、SQL 执行、结果集遍历讲透同时把 AI 辅助编码工具比如 Claude Code 这类需要统一 Key/API 通道的客户端的settings.json配置一起跑通。你照着做本地环境就能跑出一套「查得到、拿得稳、改得动」的读写流程。2. 前置准备TaoToken 统一 Key 与本地 MySQL 环境在写游标代码之前先把两件事备齐一个是数据库本身一个是 AI 编码工具要用的 API 通道。前者决定你能不能连上后者决定你写代码时有没有智能补全和排错建议。MySQL 这边本地装好服务后确认有可用的库和表。我习惯用一个测试库huangwei里面放一张student表字段至少包含sname姓名和ssex性别。建表语句可以这样CREATE DATABASE IF NOT EXISTS huangwei DEFAULT CHARSET utf8mb4; USE huangwei; CREATE TABLE IF NOT EXISTS student ( id INT PRIMARY KEY AUTO_INCREMENT, sname VARCHAR(32) NOT NULL, ssex VARCHAR(4) NOT NULL ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; INSERT INTO student (sname, ssex) VALUES (周梅,女),(李强,男),(王芳,女),(赵磊,男);Python 侧只需要一个驱动pymysql足够轻量pip install pymysqlAI 编码工具这边如果你用的是需要配置settings.json的客户端核心是把请求地址指向统一通道。TaoToken 的 API 入口是https://taotoken.net/api官网在https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。Key 的申请和查看在控制台的 API Keys 页面地址是https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite。拿到 Key 之后模型对话入口在https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite接入文档在https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite。注意Key 只存在本地配置文件里不要提交到 Git也不要在截图里露出完整字符串。3. 可复制配置settings.json 骨架与 pymysql 连接参数先给 AI 编码工具的settings.json一个可用的骨架。不同客户端字段名略有差异但思路一致把 base URL 指向 TaoToken 的 API 地址把 Key 填进对应字段。下面这份是通用结构你按自己客户端的字段名微调即可{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: sk-你的TaoTokenKey, ANTHROPIC_MODEL: claude-sonnet-4-20250514 }, permissions: { allow: [Read, Write, Bash(python:*)] } }如果你用的是 Claude Code 这类命令行工具配置路径通常在用户目录下的.claude/settings.json改完重启终端生效。想确认通道是否通可以直接在模型对话页发一条测试消息地址是https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite。数据库连接参数这边pymysql.connect()的常用字段如下表建议对照自己的环境逐项确认参数含义示例值易错点host数据库主机localhost写错成 http 前缀会报错port端口3306默认 3306改过要同步user用户名root权限不足会拒绝连接password密码你的密码含特殊字符要转义db目标库huangwei不写则需 SQL 里带库名charset字符集utf8mb4写 utf8 可能丢 emoji把这些参数写进一个连接函数后面所有游标操作都复用它import pymysql def get_conn(): return pymysql.connect( hostlocalhost, port3306, userroot, password你的密码, dbhuangwei, charsetutf8mb4, cursorclasspymysql.cursors.Cursor )cursorclass这一项很关键。默认返回元组如果你想要字典形式字段名做 key可以换成pymysql.cursors.DictCursor遍历时用row[sname]取值可读性更好。4. 游标实战execute、fetchone、fetchall 与结果集遍历游标的标准五步是连接、开游标、执行 SQL、取数据、关连接。先看最基础的fetchone()逐条读取conn get_conn() cursor conn.cursor() cursor.execute(select sname, ssex from student) while True: row cursor.fetchone() if row is None: break sname, ssex row if ssex 女: print(我叫{}我是一个学生.format(sname)) cursor.close() conn.close()fetchone()每次返回一个元组取完返回None所以用while True加break是最稳的写法。这里有个坑如果你先执行了一次select count(*)拿到总数再执行select sname, ssex两次execute会共用同一个游标前一次的结果集会被覆盖。所以要么重新开游标要么把计数和明细分成两次独立操作。fetchall()则一次性把剩余结果全取回来返回元组列表适合数据量不大的场景conn get_conn() cursor conn.cursor() cursor.execute(select sname, ssex from student) rows cursor.fetchall() for sname, ssex in rows: if ssex 女: print(我叫{}我是一个学生.format(sname)) cursor.close() conn.close()数据量大时别用fetchall()几万行一次性加载进内存会拖慢甚至撑爆进程。这时候用fetchmany(size)分批取比如每批 500 条cursor.execute(select sname, ssex from student) while True: batch cursor.fetchmany(500) if not batch: break for sname, ssex in batch: print(sname, ssex)写入操作同样走游标但必须commit()否则数据不会真正落库conn get_conn() cursor conn.cursor() try: cursor.execute( insert into student (sname, ssex) values (%s, %s), (孙悦, 女) ) conn.commit() print(影响行数:, cursor.rowcount) except Exception as e: conn.rollback() print(写入失败已回滚:, e) finally: cursor.close() conn.close()注意 SQL 里的占位符用%s参数以元组传入不要用字符串拼接否则会有注入风险。cursor.rowcount能告诉你这次操作影响了几行调试时很有用。5. 验证请求跑通一次完整读写并确认结果配置和代码都就位后做一次端到端验证。先确认 AI 编码通道可用在客户端里让它生成一段「查询 student 表并打印女生姓名」的代码如果能正常返回且语法正确说明settings.json里的 base URL 和 Key 生效了。如果返回鉴权错误回到 API Keys 页面核对 Key 是否复制完整。再验证数据库链路。把下面这段完整脚本存成demo.py运行import pymysql conn pymysql.connect( hostlocalhost, port3306, userroot, password你的密码, dbhuangwei, charsetutf8mb4 ) cursor conn.cursor() cursor.execute(select count(*) from student) total cursor.fetchone()[0] print(总人数:, total) cursor.execute(select sname, ssex from student) for sname, ssex in cursor.fetchall(): if ssex 女: print(我叫{}我是一个学生.format(sname)) cursor.close() conn.close()预期输出类似总人数: 5 我叫周梅我是一个学生 我叫王芳我是一个学生 我叫孙悦我是一个学生如果总人数对得上、女生姓名都打印出来说明连接、游标、结果集遍历这条链路完全通了。此时你再去改 SQL 条件、换DictCursor、加fetchmany分批都是在这个稳定基础上做增量不会一改就崩。6. 本篇常见错排查连接失败、游标报错与编码乱码报错Access denied for user rootlocalhost密码错了或者该用户没有从 localhost 连接的权限。先在 MySQL 命令行里用同样账号密码登录验证确认无误再回来看 Python 代码。注意配置文件里的密码如果含#、等字符要确保没有被 JSON 或 shell 提前解析。报错Unknown database huangwei库名拼错或者库根本没建。执行show databases;确认存在不存在就补建。报错(0, )或连接直接卡住多半是 host 或 port 写错。本地服务默认localhost:3306如果你改过端口连接参数要同步。另外确认 MySQL 服务本身在运行。cursor.execute后fetchone返回NoneSQL 没查到任何行或者前一次execute已经把结果集消耗完了。每次查询前确认游标状态必要时重新cursor.execute。中文乱码连接参数charset写utf8mb4建库建表也用utf8mb4。如果历史数据已经是乱码需要重新导入光改连接参数救不回来。写入后查询不到新数据忘了conn.commit()。pymysql 默认不开自动提交增删改必须显式提交否则连接关闭时回滚。AI 编码工具报 401/403settings.json里的 Key 失效或 base URL 写错。确认地址是https://taotoken.net/apiKey 从控制台重新复制一次。长期做编码和 Agent 任务的话可以考虑 Coding Plan入口在https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite比按次调用更适合高频场景。排障时如果拿不准配置格式直接翻接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite里面有各客户端的字段对照。Key 管理统一在https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite换 Key、看用量都在这里。7. 把游标用顺之后你的 PythonMySQL 才算真正入门游标不是什么高深概念它就是「先存后取」的那根指针。把execute和fetch*拆开理解你就能在拿到数据之后随意用 Python 做二次加工——筛选、拼接、分组、写回全都建立在干净的结果集之上。配合 TaoToken 统一 Key 通道AI 编码工具能在你写 SQL 和排错时给出即时建议settings.json配一次后面长期受益。下一步可以试试把DictCursor和fetchmany组合起来处理大表或者用上下文管理器with conn.cursor() as cursor:自动释放资源。这些都是在今天这套跑通的链路上做增量不会推翻重来。