ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

明明sql有数据的python self.cursor.execute()返回数据为空:用TaoToken统一Key排查pymysql autocommit与连接配置

明明sql有数据的python self.cursor.execute()返回数据为空:用TaoToken统一Key排查pymysql autocommit与连接配置 1. 明明 SQL 有数据self.cursor.execute() 却返回空先别怀疑人生如果你正在用 Python pymysql 写数据脚本遇到过一个非常反直觉的现象在 Navicat、DBeaver 或者命令行里执行同一条 SQL明明能查出几十上百行数据但代码里self.cursor.execute(sql)之后fetchall()却拿到一个空列表[]rowcount还是 0 或者 -1。这不是数据库坏了也不是你的 SQL 写错了绝大多数情况下是连接配置和事务行为在作怪。这个场景特别常见于「批量执行多条 case」的脚本里你写了一个类封装了self.conn、self.cursor循环跑多个查询前几条正常后面突然全空或者本地调试时能查到放到定时任务里就查不到。核心原因通常集中在三块pymysql 默认不开 autocommit、连接参数里的字符集/库名/端口对不上、以及游标类型和事务隔离级别导致读到了「旧快照」。这篇内容我会按「先定位问题 → 再统一配置 → 再接入 AI 工具做日志分析 → 最后给最小验证脚本」的顺序讲所有配置和命令都能直接复制。适合正在写 Python 数据脚本、做自动化报表、或者用 AI 辅助排查数据库问题的同学。文中会用到 TaoToken 的统一 Key 来接入模型做日志分析官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end API 地址是 https://taotoken.net/api 后面会给具体配置。2. 为什么 SQL 客户端有数据pymysql 却返回空2.1 autocommit 默认关闭事务没提交pymysql 的connect()默认autocommitFalse。这意味着你执行 INSERT/UPDATE 后不 commit数据不会落库同样在某些存储引擎和隔离级别下你的 SELECT 可能读的是事务开始时的快照而不是最新提交的数据。如果你的脚本里先做了一批写操作再查同一张表就可能读到「写之前」的状态看起来就是空。最直接的修复就是在连接时加上autocommitTrueimport pymysql conn pymysql.connect( host127.0.0.1, port3306, userapp_user, passwordyour_password, databasedemo_db, charsetutf8mb4, autocommitTrue, # 关键自动提交避免事务快照问题 cursorclasspymysql.cursors.DictCursor, )2.2 连接参数对不上查的是另一个库本地客户端连的是demo_db代码里database写成了test_db或者端口写成了 3307host 写成了内网地址。这种情况下 SQL 语法没错但查的表根本不存在数据返回空是正常的。排查时先把连接参数打印出来和客户端里的连接信息逐项对照。2.3 游标读取方式不对cursor.execute()只是执行不会自动返回数据。你必须调用fetchone()、fetchall()或fetchmany()。另外SSCursor流式游标和普通Cursor的行为不同流式游标在连接被复用或提前关闭时会读不到数据。如果你在类里复用了self.cursor前一次fetchall()已经把结果集读完下一次再fetchall()自然为空。2.4 事务隔离级别与长连接MySQL 默认隔离级别是 REPEATABLE READ。在一个长连接里第一次 SELECT 会建立快照后续 SELECT 都读这个快照。如果你的脚本是常驻进程连接一直不关就会一直读到旧数据。解决办法是每次查询前conn.commit()或conn.rollback()结束当前事务或者干脆用短连接 autocommit。3. TaoToken 前置统一 Key 接入 AI 工具做日志分析排查这类问题时日志量往往很大手动翻很痛苦。我习惯把 pymysql 的报错日志、SQL 执行记录丢给 AI 做归纳快速定位是连接问题还是事务问题。TaoToken 提供统一 Key兼容主流模型接口配置一次就能在多个工具里复用。3.1 获取 Key 与配置入口先到控制台创建 API Key入口在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。创建后复制 Key注意不要提交到 Git。3.2 config.toml 骨架如果你用支持 TOML 配置的工具比如一些 CLI 客户端可以这样写# config.toml [taotoken] api_key sk-你的TaoTokenKey base_url https://taotoken.net/api model claude-3-5-sonnet [taotoken.log_analysis] max_tokens 4096 temperature 0.23.3 settings.json 骨架如果你用的是 VS Code 插件或 Node 类工具用 JSON{ taotoken: { apiKey: sk-你的TaoTokenKey, baseUrl: https://taotoken.net/api, model: claude-3-5-sonnet, logAnalysis: { maxTokens: 4096, temperature: 0.2 } } }注意base_url 只写到/api不要自己拼/v1/chat/completions具体路径由客户端处理。模型名按你实际可用的填写。3.4 用统一 Key 做日志分析把 pymysql 的异常堆栈和 SQL 日志贴给模型让它帮你判断是 autocommit 问题还是连接参数问题。比如你可以这样提问以下是我 pymysql 执行查询的日志SQL 在客户端能查到数据但代码返回空 请帮我判断是连接配置、autocommit 还是游标读取的问题并给出修改建议 粘贴日志模型对话入口在 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 可以直接在网页里试。如果你长期写数据脚本、做 Agent 自动化建议看 Coding Plan入口是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。4. 可复制的 pymysql 配置与最小验证脚本4.1 推荐的连接封装下面这个类把 autocommit、字符集、游标类型都固定好避免每次手写出错import pymysql from pymysql.cursors import DictCursor class MySQLClient: def __init__(self, host, port, user, password, database): self.conn pymysql.connect( hosthost, portport, useruser, passwordpassword, databasedatabase, charsetutf8mb4, autocommitTrue, cursorclassDictCursor, connect_timeout10, read_timeout30, ) self.cursor self.conn.cursor() def query(self, sql, argsNone): # 每次查询前结束上一个事务避免快照读 self.conn.commit() self.cursor.execute(sql, args) return self.cursor.fetchall() def close(self): self.cursor.close() self.conn.close()4.2 最小验证脚本把下面这段保存成check_query.py改掉连接参数后直接运行from check_query import MySQLClient # 或把类定义放同一个文件 client MySQLClient( host127.0.0.1, port3306, userapp_user, passwordyour_password, databasedemo_db, ) # 先确认连接到了哪个库 print(当前库:, client.query(SELECT DATABASE() AS db)) # 确认 autocommit 状态 print(autocommit:, client.query(SELECT autocommit AS ac)) # 查目标表 rows client.query(SELECT id, name FROM your_table LIMIT 5) print(行数:, len(rows)) print(数据:, rows) client.close()运行后如果行数大于 0说明配置正确如果还是 0看下一节的排查清单。4.3 参数对照表参数推荐值作用autocommitTrue避免事务快照导致读到旧数据charsetutf8mb4防止中文乱码导致查询条件不匹配cursorclassDictCursor返回字典便于调试connect_timeout10避免连接卡死read_timeout30避免大查询无限等待5. 本篇常见错排查5.1 报错(0, )或 rowcount 为 -1这是 pymysql 在 autocommitFalse 且未 commit 时的典型表现。加上autocommitTrue或在查询前conn.commit()。5.2 查询条件里的中文匹配不到客户端里能查到代码里查不到往往是字符集问题。连接参数加charsetutf8mb4并确认表字段也是 utf8mb4。5.3 长连接读到旧数据常驻脚本里连接一直不关REPEATABLE READ 快照不更新。每次查询前conn.commit()或conn.rollback()或者改用短连接。5.4 游标复用导致第二次 fetchall 为空fetchall()会读完结果集同一个游标再查需要重新execute()。如果封装了self.cursor确保每次查询都重新执行不要复用旧结果。5.5 连接参数写错把 host、port、user、database 打印出来和客户端连接信息逐项核对。特别注意端口和库名。5.6 用 AI 辅助排查把报错堆栈和 SQL 日志贴到模型对话里让它帮你判断。入口https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有完整的接口说明。6. 接入与排障入口如果你已经确认是连接配置或 autocommit 问题直接按第 4 节的脚本改就行。需要统一 Key 做日志分析、或者长期写数据脚本和 Agent可以从下面入口进排障与接入API Keys 在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite验证模型效果模型对话在 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite长期编码与 AgentCoding Plan 在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite最后留一个我踩过的坑如果你的脚本里既有写操作又有读操作且用了同一个连接务必在每次读之前 commit 一次否则读到的永远是事务开始时的快照。这个细节在本地小数据量时不容易发现数据一多、脚本一常驻就会暴露。
返回列表