持续运行的Python脚本中数据库连接的优化策略咨询
优化持续运行Python脚本的数据库连接与异常处理方案
嘿,你的问题我太懂了——长连接容易丢,每次重连又嫌麻烦,还得天天重启脚本,确实闹心。下面给你几个实用的解决方案,一步步帮你搞定:
方案1:使用数据库连接池(最推荐)
连接池会帮你管理一组数据库连接,自动处理连接的创建、复用和失效回收,完美平衡“避免频繁重连”和“防止连接失效”的矛盾。用mysql.connector自带的连接池就能实现:
import mysql.connector from mysql.connector import pooling import schedule import time # 初始化连接池 dbconfig = { "user": DB_USER, "password": DB_PASSWORD, "host": "XYZ", "database": DB_NAME, } cnxpool = mysql.connector.pooling.MySQLConnectionPool( pool_name="mypool", pool_size=5, # 单线程任务设置1个也足够,按需调整 **dbconfig ) def job(): cnx = None cursor = None try: # 从连接池获取连接 cnx = cnxpool.get_connection() cursor = cnx.cursor() # 执行你的解析和数据库操作 run_parser1(cnx, cursor) run_parser2(cnx, cursor) cnx.commit() # 别忘了提交事务 except mysql.connector.Error as db_err: print(f"数据库错误: {db_err}") if cnx: cnx.rollback() # 出错回滚事务 except Exception as e: print(f"其他错误: {e}") finally: # 关闭游标和连接(连接会放回连接池,并非真正关闭) if cursor: cursor.close() if cnx: cnx.close() schedule.every(30).seconds.do(job) while True: schedule.run_pending() time.sleep(1)
连接池会自动处理连接有效性,如果某个连接失效,下次get_connection()会自动创建新连接,完全不用你手动操心。
方案2:任务前检查连接有效性,失效则重连
如果不想用连接池,也可以在每次任务执行前先验证当前连接是否可用,失效就重新建立:
import mysql.connector import schedule import time cnx = None cursor = None def get_valid_connection(): global cnx, cursor try: # 检查连接是否存活 if cnx and cnx.is_connected(): return cnx, cursor # 连接失效或未初始化,重新建立 cnx = mysql.connector.connect(user=DB_USER, password=DB_PASSWORD, host='XYZ', database=DB_NAME) cursor = cnx.cursor() return cnx, cursor except Exception as e: print(f"重新连接数据库失败: {e}") # 清理无效连接 if cnx: try: cnx.close() except: pass if cursor: try: cursor.close() except: pass cnx = None cursor = None raise # 抛出异常让上层处理 def job(): try: cnx, cursor = get_valid_connection() # 执行解析和数据库操作 run_parser1(cnx, cursor) run_parser2(cnx, cursor) cnx.commit() except Exception as e: print(f"任务执行失败: {e}") # 网络类错误可以跳过本次任务,不影响后续执行 schedule.every(30).seconds.do(job) while True: schedule.run_pending() time.sleep(1)
这个方案既保持了连接复用,又能确保每次任务用的都是活连接,避免了连接丢失导致的报错。
方案3:异常捕获后自动重建连接,不中断脚本
针对你之前代码的问题——一旦job里出现异常关闭了连接,后续任务就会因为cnx/cursor已关闭而失败。可以修改异常处理逻辑,在捕获到连接相关异常时自动重建连接:
import mysql.connector import schedule import time cnx = None cursor = None def init_connection(): global cnx, cursor try: cnx = mysql.connector.connect(user=DB_USER, password=DB_PASSWORD, host='XYZ', database=DB_NAME) cursor = cnx.cursor() print("数据库连接建立成功") except Exception as e: print(f"初始化连接失败: {e}") raise # 初始化初始连接 init_connection() def job(): global cnx, cursor try: # 自动检查并重建连接 cnx.ping(reconnect=True) # 执行解析和数据库操作 run_parser1(cnx, cursor) run_parser2(cnx, cursor) cnx.commit() except mysql.connector.Error as db_err: print(f"数据库错误,尝试重建连接: {db_err}") # 清理旧连接 try: cursor.close() cnx.close() except: pass # 重新初始化连接 init_connection() except Exception as e: print(f"解析或其他错误: {e}") cnx.rollback() # 出错回滚事务 schedule.every(30).seconds.do(job) while True: schedule.run_pending() time.sleep(1)
这里用了cnx.ping(reconnect=True),它会自动检查连接状态,如果断开就尝试重连;就算重连失败,也会捕获异常并重新初始化连接,不会让脚本直接挂掉。
额外小贴士
- 事务处理:数据库操作后一定要
commit(),出错时记得rollback(),避免数据不一致。 - 日志记录:用
logging模块把错误信息详细记录到文件,方便后续排查问题。 - 站点异常隔离:在
run_parser里单独捕获网络异常(比如requests.exceptions.RequestException),别让站点不可用的问题连累数据库连接。 - 优雅退出:给脚本加信号处理(比如
SIGINT),收到退出信号时先关闭数据库连接再退出,避免连接泄漏。
内容的提问来源于stack exchange,提问作者BanikPyco
相关产品推荐
相关产品推荐

