资讯动态

pymysql.Error 错误码与错误信息获取:TaoToken 统一 Key 下的配置骨架与验证动作

发布时间:2026/9/28 21:35:43 来源:尧图企业网站定制
1. 为什么 pymysql.Error 的 errno 和 message 总是抓不全写 Python 连 MySQL 的时候最让人抓狂的不是报错本身而是报错信息只给你半截。比如你执行一条插入语句控制台只打印一句(1062, Duplicate entry 1 for key PRIMARY)你知道是主键冲突但不知道是哪张表、哪条 SQL、哪个连接参数触发的。更麻烦的是很多同学在except里只写print(e)结果e.args里明明有两个元素却只看到一坨字符串想拿errno做分支判断都无从下手。pymysql.Error是 pymysql 所有异常的基类它继承自 Python 内置的Exception。当你捕获到它时e.args通常是一个元组第一个元素是 MySQL 服务端返回的错误码errno第二个元素是具体的错误描述message。但这里有个坑并不是所有异常都严格遵循这个结构。比如连接阶段的OperationalError有时候args只有一个元素直接写e.args[1]就会抛IndexError把真正的数据库错误给盖掉了。我试过在一个批量导入脚本里因为没做args长度判断结果 2000 条数据导入失败日志里全是IndexError: tuple index out of range完全看不到 MySQL 到底报了什么。后来把异常捕获逻辑重写才定位到是某个字段超长触发了1406 Data too long。所以这一篇我们就聚焦在「怎么稳定拿到 errno 和 message」这件事上同时给出一套在 TaoToken 统一 Key 通道下可复制的配置骨架和验证脚本。TaoToken 在这里的角色是帮你把模型调用和数据库排障辅助统一到一个 Key 下管理。你可以在同一个控制台里管理 API Key用模型对话快速分析报错日志用 Coding Plan 做长期脚本维护。官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 注意 API 地址不带 UTM 参数。2. TaoToken 前置统一 Key 与配置骨架准备在写数据库异常捕获之前先把 TaoToken 的 Key 和配置文件准备好。这一步不是必须的但如果你希望后续用模型辅助分析pymysql.Error的报错信息统一 Key 会让整个流程顺很多。你不需要在多个平台之间切换一个 Key 就能覆盖模型对话、编码计划、控制台管理。2.1 获取 API Key 与目录结构先到控制台创建 API Key地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 。创建完之后建议把 Key 放到环境变量里不要硬编码在脚本中。我习惯在项目根目录建一个config.toml再配一个settings.json给不同环境用。目录结构大概长这样project/ ├── config.toml ├── settings.json ├── db_check.py └── logs/ └── pymysql_error.logconfig.toml负责放数据库连接参数和 TaoToken 的 API 地址settings.json负责放运行时的开关比如是否开启详细日志、是否用模型辅助分析。这样拆开的好处是数据库密码不会跟着代码进 Git而模型相关的配置可以单独调整。2.2 config.toml 骨架# config.toml [mysql] host 127.0.0.1 port 3306 user root password your_password database test_db charset utf8mb4 connect_timeout 5 [taotoken] api_base https://taotoken.net/api api_key_env TAOTOKEN_API_KEY model claude-sonnet这里api_base固定写https://taotoken.net/api不要加 UTM。api_key_env指向环境变量名脚本运行时从环境变量读取避免明文泄露。2.3 settings.json 骨架{ log_level: DEBUG, log_file: logs/pymysql_error.log, enable_model_analysis: true, max_retry: 3, retry_backoff: 1.5 }enable_model_analysis打开后脚本在捕获到pymysql.Error时可以把 errno 和 message 整理成一段提示通过 TaoToken 的模型对话接口做进一步解释。模型对话入口在 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 你可以先在网页上试一下报错分析的效果再决定要不要集成到脚本里。3. 可复制配置pymysql.Error 异常捕获骨架这一节是核心。我们要写一个能稳定提取 errno 和 message 的捕获函数并且把它和配置文件串起来。先看完整的db_check.py然后逐段解释。3.1 读取配置与建立连接# -*- coding: utf-8 -*- import os import json import time import logging import traceback import pymysql import tomllib # Python 3.11低版本用 tomli # 读取 config.toml with open(config.toml, rb) as f: config tomllib.load(f) # 读取 settings.json with open(settings.json, r, encodingutf-8) as f: settings json.load(f) # 配置日志 logging.basicConfig( levelgetattr(logging, settings[log_level]), format%(asctime)s [%(levelname)s] %(message)s, handlers[ logging.FileHandler(settings[log_file], encodingutf-8), logging.StreamHandler() ] ) logger logging.getLogger(__name__) def get_connection(): mysql_cfg config[mysql] return pymysql.connect( hostmysql_cfg[host], portmysql_cfg[port], usermysql_cfg[user], passwordmysql_cfg[password], databasemysql_cfg[database], charsetmysql_cfg[charset], connect_timeoutmysql_cfg[connect_timeout], cursorclasspymysql.cursors.DictCursor )这里用tomllib读 TOMLPython 3.11 以上自带。如果你用的是 3.10 或更低装一个tomli就行导入语句改成import tomli as tomllib。日志同时输出到文件和控制台方便你一边跑一边看。3.2 稳定提取 errno 与 message 的函数def extract_pymysql_error(e): 从 pymysql.Error 中稳定提取 errno 和 message。 返回 (errno, message, raw_args) raw_args getattr(e, args, ()) errno None message str(e) if isinstance(raw_args, (tuple, list)): if len(raw_args) 2: errno raw_args[0] message raw_args[1] elif len(raw_args) 1: # 只有一个元素时尝试判断是不是纯数字错误码 first raw_args[0] if isinstance(first, int): errno first message else: message str(first) return errno, message, raw_args这个函数的关键在于不假设args一定有俩元素。len(raw_args) 2时才取raw_args[0]和raw_args[1]只有一个元素时判断它是不是整数是整数就当 errno否则当 message。这样即使遇到连接超时这种args只有一个字符串的异常也不会抛IndexError。3.3 带重试和日志的查询封装def execute_sql(sql, paramsNone): conn None cursor None attempt 0 max_retry settings[max_retry] backoff settings[retry_backoff] while attempt max_retry: try: conn get_connection() cursor conn.cursor() cursor.execute(sql, params) conn.commit() logger.info(SQL 执行成功: %s, sql) return cursor.fetchall() if cursor.description else None except pymysql.Error as e: errno, message, raw_args extract_pymysql_error(e) logger.error( pymysql.Error | errno%s | message%s | raw_args%s, errno, message, raw_args ) logger.debug(完整堆栈:\n%s, traceback.format_exc()) # 针对特定错误码做分支处理 if errno 1062: logger.warning(主键或唯一索引冲突跳过本条) return None if errno 1406: logger.warning(字段超长检查表结构) return None if errno in (2003, 2006): logger.warning(连接层错误准备重试) attempt 1 if attempt max_retry: logger.error(达到最大重试次数放弃) raise time.sleep(backoff ** attempt) finally: if cursor: cursor.close() if conn: conn.close()这段代码把「提取错误码」和「按错误码分支」结合起来了。1062是唯一索引冲突1406是数据超长2003和2006是连接层错误。你可以根据自己的业务往里面加更多 errno 分支。注意finally里关闭游标和连接避免连接泄漏。3.4 模型辅助分析的可选接入如果你在settings.json里把enable_model_analysis设为true可以在捕获异常后把 errno 和 message 拼成一段提示调用 TaoToken 的模型对话接口。这里给一个用requests的示例import requests def analyze_with_model(errno, message): api_key os.environ.get(config[taotoken][api_key_env]) if not api_key: logger.warning(未设置 TAOTOKEN_API_KEY跳过模型分析) return None prompt ( fMySQL 报错 errno{errno}, message{message}。 请用中文解释这个错误的常见原因和排查步骤控制在 200 字以内。 ) resp requests.post( f{config[taotoken][api_base]}/v1/chat/completions, headers{Authorization: fBearer {api_key}}, json{ model: config[taotoken][model], messages: [{role: user, content: prompt}] }, timeout30 ) if resp.status_code 200: return resp.json()[choices][0][message][content] logger.warning(模型分析请求失败: %s, resp.status_code) return None这段代码是可选的不影响主流程。模型对话的网页入口在 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 你可以先手动试几条报错看看返回质量再决定是否集成。4. 验证请求与成功结果配置写完了得跑一次验证确认 errno 和 message 能正确提取。我们设计三个场景正常查询、主键冲突、字段超长。4.1 准备测试表CREATE TABLE IF NOT EXISTS user_test ( id INT PRIMARY KEY, name VARCHAR(10) NOT NULL, email VARCHAR(50) UNIQUE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;name字段限长 10email有唯一索引方便制造1406和1062。4.2 验证脚本if __name__ __main__: # 场景一正常插入 execute_sql(INSERT INTO user_test (id, name, email) VALUES (%s, %s, %s), (1, alice, aliceexample.com)) # 场景二主键冲突触发 1062 execute_sql(INSERT INTO user_test (id, name, email) VALUES (%s, %s, %s), (1, bob, bobexample.com)) # 场景三字段超长触发 1406 execute_sql(INSERT INTO user_test (id, name, email) VALUES (%s, %s, %s), (2, a_very_long_name_exceeding_ten, longexample.com))4.3 预期日志输出跑完之后logs/pymysql_error.log里应该能看到类似这样的记录2025-01-15 10:30:01 [INFO] SQL 执行成功: INSERT INTO user_test ... 2025-01-15 10:30:01 [ERROR] pymysql.Error | errno1062 | messageDuplicate entry 1 for key PRIMARY | raw_args(1062, Duplicate entry 1 for key PRIMARY) 2025-01-15 10:30:01 [WARNING] 主键或唯一索引冲突跳过本条 2025-01-15 10:30:02 [ERROR] pymysql.Error | errno1406 | messageData too long for column name at row 1 | raw_args(1406, Data too long for column name at row 1) 2025-01-15 10:30:02 [WARNING] 字段超长检查表结构看到errno1062和errno1406被单独打出来说明提取逻辑生效了。raw_args也完整保留方便你排查那些结构不标准的异常。如果你开启了模型分析日志里还会多一段中文解释。4.4 连接层错误的验证把config.toml里的port改成3307一个不存在的端口再跑一次。你会看到2025-01-15 10:35:00 [ERROR] pymysql.Error | errno2003 | messageCant connect to MySQL server on 127.0.0.1 ([Errno 111] Connection refused) | raw_args(2003, Cant connect to MySQL server on 127.0.0.1 ([Errno 111] Connection refused))这里args有两个元素提取正常。如果你遇到某些驱动版本只返回一个字符串我们的extract_pymysql_error也能兜住不会崩。5. 本篇常见错排查5.1 e.args[1] 报 IndexError这是最常见的坑。原因就是某些pymysql.Error子类的args只有一个元素。解决办法就是本篇的extract_pymysql_error先判断长度再取值。如果你不想写函数至少写成errno e.args[0] if len(e.args) 0 else None message e.args[1] if len(e.args) 1 else str(e)5.2 errno 是字符串而不是整数有些环境里args[0]可能是字符串形式的数字比如1062。这时候你做if errno 1062判断会失败。可以在提取后加一层转换if isinstance(errno, str) and errno.isdigit(): errno int(errno)5.3 捕获了 pymysql.Error 但没捕获子类pymysql.Error是基类OperationalError、IntegrityError、ProgrammingError都是它的子类。用except pymysql.Error能捕获所有子类但如果你只写了except pymysql.OperationalError那1062这种IntegrityError就漏掉了。建议统一用基类捕获再按 errno 分支。5.4 日志里看不到完整堆栈logger.error默认只打消息不打堆栈。想看堆栈得用logger.exception或者在error里手动加traceback.format_exc()。本篇的代码用的是后者这样堆栈和 errno 在同一行日志里排查更快。5.5 连接没关闭导致重试时端口耗尽在finally里关闭连接是必须的。如果你在except里直接raise而没有finally连接对象可能一直挂着。重试次数多了MySQL 的max_connections会被打满报1040 Too many connections。这个 errno 也可以加到你的分支里。5.6 TaoToken Key 没设置导致模型分析静默失败如果你开了enable_model_analysis但没设TAOTOKEN_API_KEY环境变量analyze_with_model会返回None日志里只有一条 warning。检查环境变量export TAOTOKEN_API_KEY你的KeyWindows 下用set TAOTOKEN_API_KEY你的Key。Key 在控制台创建地址是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。6. 接入文档与长期维护建议数据库报错处理不是一次性的活。表结构会变MySQL 版本会升级pymysql 的异常结构也可能微调。建议把extract_pymysql_error单独放到一个db_utils.py里所有项目共用。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有 API 的详细参数说明你可以对照着调整模型分析的请求体。如果你打算长期维护这类脚本甚至做成定时任务或者 Agent 自动巡检可以了解一下 Coding Plan入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。它适合需要持续迭代的编码场景把 Key 管理和模型调用统一起来省得每次换项目都要重新配一遍。最后给一个实用小技巧在settings.json里加一个error_code_map把常见的 errno 和中文解释对应起来脚本启动时加载到内存。这样即使不调模型日志里也能直接看到「1062 唯一索引冲突」这样的提示排查速度会快很多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑