You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python MySQL连接异常重连求助:树莓派跨机连接中断故障

解决树莓派间MySQL连接中断后的自动恢复问题

这是嵌入式设备做远程数据库访问时非常常见的痛点——当远端数据库服务器(你的SolarPi)重启后,本地客户端(OfficePi)的旧连接会失效,要是没做处理,脚本很容易陷入无限错误循环。我之前在树莓派做物联网数据采集时也遇到过一模一样的问题,给你几个亲测有效的解决思路:

1. 给数据库连接加上重试逻辑

把连接数据库的代码封装成带重试的函数,当捕获到连接异常时,间隔一段时间重新尝试连接,避免一次性失败就崩溃。这里用指数退避的方式(等待时间递增),既保证重试效率,又不会频繁请求占用资源:

import mysql.connector
from mysql.connector import Error
import time

def get_db_connection(host, user, password, db_name):
    conn = None
    retry_count = 0
    max_retries = 10  # 可根据需求调整重试上限
    while conn is None and retry_count < max_retries:
        try:
            conn = mysql.connector.connect(
                host=host,
                user=user,
                password=password,
                database=db_name
            )
            print("成功重新连接到数据库")
        except Error as e:
            print(f"连接失败,错误信息: {e}")
            retry_count += 1
            wait_time = 2 ** retry_count  # 指数退避:2秒、4秒、8秒...
            print(f"{wait_time}秒后重试...")
            time.sleep(wait_time)
    if conn is None:
        raise Exception("达到最大重试次数,无法连接数据库")
    return conn

2. 每次操作前检查连接有效性

有时候连接对象看似存在,但底层TCP连接已经因为SolarPi重启断开了,直接执行SQL会报错。可以在操作前用ping()方法检查连接,mysql-connector-python支持ping(reconnect=True)参数,能自动重连失效连接:

def execute_query(conn, query, params=None):
    cursor = None
    try:
        # 检查连接有效性,失效则自动重连
        conn.ping(reconnect=True)
        cursor = conn.cursor()
        if params:
            cursor.execute(query, params)
        else:
            cursor.execute(query)
        conn.commit()
        return cursor.fetchall() if cursor.with_rows else None
    except Error as e:
        print(f"执行查询出错: {e}")
        # 重连失败时主动抛出异常,让上层逻辑重新获取连接
        raise
    finally:
        if cursor:
            cursor.close()

3. 主循环中捕获异常并重置连接

把数据库读写逻辑放在主循环里,一旦捕获到连接相关异常(比如OperationalError),就销毁旧连接,重新调用连接函数获取新连接,避免脚本陷入错误循环:

def main():
    db_config = {
        "host": "SolarPi的IP地址",
        "user": "你的数据库用户名",
        "password": "你的数据库密码",
        "database": "数据采集库名"
    }
    conn = get_db_connection(**db_config)
    
    while True:
        try:
            # 替换成你的实际数据读写逻辑
            sensor_data = read_office_sensor()  # 假设这是你的数据读取函数
            execute_query(conn, "INSERT INTO sensor_records (value) VALUES (%s)", (sensor_data,))
            time.sleep(60)  # 每分钟采集一次
        except Error as e:
            print(f"主循环连接出错: {e}")
            print("尝试重新建立数据库连接...")
            if conn:
                conn.close()
            conn = get_db_connection(**db_config)
        except Exception as e:
            print(f"其他非连接类错误: {e}")
            time.sleep(60)

if __name__ == "__main__":
    main()

可选:用连接池更优雅管理连接

如果你的脚本是长期运行的服务,用连接池可以自动处理失效连接的回收和重建,比如SQLAlchemy的连接池:

from sqlalchemy import create_engine
from sqlalchemy.exc import OperationalError
import time

# 创建连接池,每小时自动回收旧连接避免失效
engine = create_engine(
    "mysql+mysqlconnector://user:password@SolarPi_IP/db_name",
    pool_size=5,
    max_overflow=10,
    pool_recycle=3600
)

def main():
    while True:
        try:
            with engine.connect() as conn:
                # 执行数据库操作
                conn.execute("INSERT INTO sensor_records (value) VALUES (%s)", (read_office_sensor(),))
                conn.commit()
            time.sleep(60)
        except OperationalError as e:
            print(f"连接失效,重新尝试: {e}")
            time.sleep(5)

这些方案可以组合使用,核心思路就是不要让连接失败直接终止脚本,通过重试、检查、重置连接的方式让脚本自动恢复运行

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

火山引擎 最新活动