You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyMySQL技术问询:获取最后SQL errno及连接池坏连接归还时剔除

嘿,针对你提出的两个PyMySQL相关问题,我结合实际开发经验来给你捋捋解决方案:

问题1:如何获取PyMySQL连接的最后一个SQL errno?

PyMySQL其实在多个层面都提供了获取错误编号的方式,核心分两种场景:

  • 捕获异常时直接获取:当执行SQL触发pymysql.MySQLError异常时,异常对象本身就携带了errno信息,你可以直接访问e.errno(PyMySQL的异常类已经封装了这个属性),也可以通过e.args[0]拿到。
  • 主动检查连接状态:即使没有抛出异常,连接对象(Connection)本身也有一个errno属性,会记录最近一次操作的错误编号,没有错误时该值为0。

给你写个实际代码示例:

import pymysql
from pymysql import MySQLError

try:
    # 建立连接
    conn = pymysql.connect(host="localhost", user="root", password="your_password", db="test_db")
    cursor = conn.cursor()
    # 执行一个会出错的SQL(比如查询不存在的表)
    cursor.execute("SELECT * FROM non_existent_table")
except MySQLError as e:
    # 从异常对象获取errno
    print(f"错误编号:{e.errno}")
    # 也可以从连接对象获取最近的错误编号
    print(f"连接记录的错误编号:{conn.errno}")
finally:
    if conn:
        conn.close()
问题2:连接归还至池时剔除已损坏连接,避免每次获取时ping

完全理解你的性能顾虑——每次获取连接都执行SELECT 1或者ping()确实会在高并发场景下带来额外开销。核心思路是在连接的生命周期内跟踪健康状态,归还时再做校验剔除,具体可以这么实现:

方案思路

  1. 给连接池中的每个连接维护一个「健康标记」,记录该连接是否在使用中出现过致命错误。
  2. 当连接在使用过程中触发了连接断开类的错误(比如errno 2006、2013这类),立即标记为「不健康」。
  3. 归还连接时,先检查健康标记和连接对象的errno,如果是损坏状态,直接关闭连接并补充新连接到池,而不是放回池内。

代码示例(自定义连接池)

假设你用自定义连接池实现,这里给你一个简化版的参考:

import pymysql
from pymysql import MySQLError
from queue import Queue

class CustomDBPool:
    def __init__(self, host, user, password, db, pool_size=5):
        self.pool = Queue(maxsize=pool_size)
        self.config = {
            "host": host,
            "user": user,
            "password": password,
            "db": db,
            "autocommit": True
        }
        # 初始化连接池,每个元素是(连接对象, 是否健康)
        for _ in range(pool_size):
            self.pool.put((self._create_conn(), True))

    def _create_conn(self):
        """创建新的数据库连接"""
        return pymysql.connect(**self.config)

    def get_conn(self):
        """从池里获取连接,这里不需要额外ping"""
        conn, is_healthy = self.pool.get()
        # 极端兜底:如果归还时漏检了,这里再替换新连接
        if not is_healthy:
            conn.close()
            conn = self._create_conn()
            is_healthy = True
        return conn, is_healthy

    def return_conn(self, conn, is_healthy):
        """归还连接时处理损坏连接"""
        # 先判断标记和连接的errno
        fatal_errnos = (2006, 2013, 2014, 2055)  # 对应连接断开、超时等致命错误
        if not is_healthy or conn.errno in fatal_errnos:
            # 损坏连接直接关闭,补充新连接到池
            conn.close()
            self.pool.put((self._create_conn(), True))
        else:
            # 健康连接放回池
            self.pool.put((conn, True))

# 使用示例
if __name__ == "__main__":
    pool = CustomDBPool(host="localhost", user="root", password="your_password", db="test_db")
    conn, is_healthy = pool.get_conn()
    try:
        cursor = conn.cursor()
        cursor.execute("INSERT INTO test_table(name) VALUES('test')")
    except MySQLError as e:
        # 如果是致命连接错误,标记为不健康
        if e.errno in (2006, 2013, 2014, 2055):
            is_healthy = False
        # 其他业务错误可以正常抛出处理
        raise
    finally:
        pool.return_conn(conn, is_healthy)

补充说明

  • 你可以根据MySQL官方的错误码列表,扩展fatal_errnos的范围,覆盖所有你认为会导致连接损坏的错误编号。
  • 这种方式只在连接出现异常或归还时做检查,避免了每次获取连接的额外开销,性能损耗几乎可以忽略。

内容的提问来源于stack exchange,提问作者Ke Lu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:49:43