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

不使用MYSQL_OPT_RECONNECT实现MySQL(MariaDB)数据库重连的方案咨询

问题描述

运行环境:Ubuntu 22.10、Qt 6.4.0、MariaDB v15.1

初始化数据库的代码如下:

Orders::Orders(QObject *parent) : QObject{parent}
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "orders");
    db.setHostName("localhost");
    db.setDatabaseName("database");
    db.setUserName("user");
    db.setPassword("password");
    db.setConnectOptions("MYSQL_OPT_RECONNECT=TRUE;");
    db.open();

    _model = new QSqlTableModel(this, db);
    _model->setTable("orders");
    _model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    _model->select();
}

运行时收到警告:

WARNING: MYSQL_OPT_RECONNECT is deprecated and will be removed in a future version.

查阅Qt文档得知官方已彻底移除自动重连功能,移除该选项后不清楚如何手动处理重连。比如以下数据库操作函数:

void Orders::setOrderState(QString machine, QString id, DbOrderStates state)
{
    QSqlDatabase db = QSqlDatabase::database("orders");
    QString sql = QString("UPDATE orders SET states_id=:state WHERE id=:id AND machine=:machine");
    QSqlQuery query(db);
    query.prepare(sql);
    query.bindValue(":state", static_cast<int>(state));
    query.bindValue(":id", id);
    query.bindValue(":machine", machine);
    query.exec();
}

疑问点:

  • 执行数据库操作时如何确保连接有效?
  • 是否需要检查prepare()返回值,失败则阻塞并重连?
  • QSqlDatabase::isOpen()仅能判断曾打开过,无法验证当前连接有效性,且无连接断开信号,该如何处理?

解决方案

1. 实现连接有效性验证函数

isOpen()只能判断连接是否被打开过,无法检测实际连接状态。可以通过执行简单SQL语句验证:

bool Orders::isDbConnectionValid(QSqlDatabase &db)
{
    if (!db.isOpen())
        return false;

    QSqlQuery query(db);
    if (query.exec("SELECT 1")) {
        return query.next(); // 能执行并获取结果则连接有效
    }
    return false;
}

2. 编写手动重连逻辑

重连时需先关闭失效连接,再重新初始化连接参数并打开,注意复用原连接名:

bool Orders::reconnectDb(QSqlDatabase &db)
{
    if (db.isOpen()) {
        db.close();
    }
    // 建议把连接参数存在类成员变量中,避免硬编码
    db.setHostName("localhost");
    db.setDatabaseName("database");
    db.setUserName("user");
    db.setPassword("password");
    db.setConnectOptions(""); // 移除废弃的重连选项
    return db.open();
}

3. 在数据库操作中集成重连逻辑

以setOrderState为例,先检查连接有效性,无效则尝试重连,重连成功后再执行操作,同时增加错误检查:

bool Orders::setOrderState(QString machine, QString id, DbOrderStates state)
{
    QSqlDatabase db = QSqlDatabase::database("orders");

    // 检查连接,无效则重连
    if (!isDbConnectionValid(db)) {
        if (!reconnectDb(db)) {
            qDebug() << "数据库重连失败";
            return false;
        }
        // 重连后更新QSqlTableModel的关联连接并刷新数据
        _model->setDatabase(db);
        _model->select();
    }

    QString sql = "UPDATE orders SET states_id=:state WHERE id=:id AND machine=:machine";
    QSqlQuery query(db);
    if (!query.prepare(sql)) {
        qDebug() << "SQL预编译失败:" << query.lastError().text();
        return false;
    }
    query.bindValue(":state", static_cast<int>(state));
    query.bindValue(":id", id);
    query.bindValue(":machine", machine);
    
    if (!query.exec()) {
        qDebug() << "SQL执行失败:" << query.lastError().text();
        // 执行失败时再次检查连接,尝试重连后重试
        if (!isDbConnectionValid(db) && reconnectDb(db)) {
            return query.exec();
        }
        return false;
    }
    return true;
}

这里把函数返回值改为bool,方便上层判断操作是否成功,避免静默失败。

4. QSqlTableModel的特殊处理

连接断开并重连后,原模型关联的是失效连接,必须调用_model->setDatabase(db)重新绑定新连接,再执行select()刷新数据,才能让模型恢复正常工作。

额外建议

  • 错误日志:所有数据库操作错误(预编译失败、执行失败、重连失败)都要记录详细日志,方便排查问题。
  • 重连次数限制:设置最大重试次数(比如3次),避免无限重试导致死循环。
  • 异步处理:如果重连可能耗时,可将重连逻辑放到子线程,避免阻塞UI线程(GUI程序适用)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 16:27:38