不使用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
相关产品推荐
相关产品推荐

