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




