iis服务器助手广告广告
返回顶部
首页 > 资讯 > 数据库 >QT实现检测MySQL数据库连接状态并断开重连
  • 805
分享到

QT实现检测MySQL数据库连接状态并断开重连

qtmysql断开重连 2023-08-20 12:08:39 805人浏览 泡泡鱼
摘要

背景 在Qt中做有关于Mysql的业务时,有时候需要知道mysql数据库的当前连接状态。但QT在提供的QsqlDatabase模块中并没有相关的功能,不像QtcpSocket在连接服务或断开服务时都有相应的信号发出。 网上方法 (1)使用Q

背景

Qt中做有关于Mysql的业务时,有时候需要知道mysql数据库的当前连接状态。但QT在提供的QsqlDatabase模块中并没有相关的功能,不像QtcpSocket在连接服务或断开服务时都有相应的信号发出。

网上方法

  • (1)使用QSqlDatabase::isOpen()判断

测试,在突然与数据库所在网络断开后,该接口仍返回true,不靠谱。

  • (2)设置连接参数setConnectOptions(“MYSQL_OPT_RECONNECT=1”)

未测试,看网上的说法是在长时间未操作(默认8小时)数据库则会与数据库断开,如设置这个参数则会重连,但不知道在断网后的情况怎样。

  • (3)定时执行sql语句来判断

使用定时器,定时执行sql语句(“select 1”)来判断数据库是否连接正常。经测试,在突然断网的情况下,执行sql语句会阻塞20秒甚至更长的时间(不知道这个时间是由什么决定的?可否设置?);但若是数据库服务挂掉,则不会阻塞。

解决方法

采用第3种方法 + 每次执行sql前ping一下网络是否连接正常,以此来避免断网时执行sql的阻塞。
(1)子线程中创建专门的连接来检测数据库连接状态;
(2)其他线程则创建自己的连接来执行相应的业务;并可根据子线程检测的状态结果来做相应的判断。
如果有别的方法,还请大佬们指导一下

代码

.h文件

#ifndef DBHEARTBEATTHREAD_H#define DBHEARTBEATTHREAD_H#include #include #include class DBHeartbeatThread : public QThread{    Q_OBJECTpublic:    enum DBType : quint8 {        MySQL = 0,        SqlServer,        oracle    };    struct ConnectParam {        QString ip;        quint16 port;        QString dbName;        QString userName;        QString passWord;    };public:    explicit DBHeartbeatThread(QObject *parent = nullptr);    explicit DBHeartbeatThread(const DBType &type, const ConnectParam &param, QObject *parent = nullptr);public:    void setDBTypeAndConnectParm(const DBType &type, const ConnectParam &param);    void setCheckIpIsOnlineInterval(int msec);    void setConnectDBInterval(int msec);    void setCheckDBHeartbeatInterval(int msec);    QString lastError() const;protected:    void run() override;signals:    void signal_connectedDB();       // 数据库连接成功    void signal_disconnectedDB();    // 与数据库断开连接    void signal_connectedNet();      // 网络连接成功    void signal_disconnectedNet();   // 网络断开连接private:    DBType m_type;    ConnectParam m_param;    int m_checkIpIsOnlineInterval;    int m_connectDBInterval;    int m_checkDBHeartbeatInterval;    QMap<DBType, QString> m_mapDBTypeDriver;    QString m_lastError;    const int kCheckIpFailTime = 3;    // 检测网络心跳失败最大次数    const int kCheckDBFailTime = 3;    // 检测数据库心跳失败最大次数};#endif // DBHEARTBEATTHREAD_H

.cpp文件

#include "dbheartbeatthread.h"#include #include #include #include #include #include #include DBHeartbeatThread::DBHeartbeatThread(QObject *parent) : QThread(parent){    m_checkIpIsOnlineInterval = 100;    m_connectDBInterval = 100;    m_checkDBHeartbeatInterval = 100;    m_lastError = "";    m_mapDBTypeDriver = {{MySQL, "QMYSQL"}, {SqlServer, "QODBC"}, {Oracle, "QOCI"}};}DBHeartbeatThread::DBHeartbeatThread(const DBType &type, const ConnectParam &param, QObject *parent)    : DBHeartbeatThread(parent){    m_type = type;    m_param = param;}void DBHeartbeatThread::setDBTypeAndConnectParm(const DBHeartbeatThread::DBType &type,        const DBHeartbeatThread::ConnectParam &param){    m_type = type;    m_param = param;}void DBHeartbeatThread::setCheckIpIsOnlineInterval(int msec){    m_checkIpIsOnlineInterval = msec;}void DBHeartbeatThread::setConnectDBInterval(int msec){    m_connectDBInterval = msec;}void DBHeartbeatThread::setCheckDBHeartbeatInterval(int msec){    m_checkDBHeartbeatInterval = msec;}QString DBHeartbeatThread::lastError() const{    return m_lastError;}void DBHeartbeatThread::run(){    /// 数据库连接异常:    /// 1、断网,用checkIpIsOnline判断    /// 2、数据库服务挂了,在MySQL上测试query.exec(sql)不会阻塞,会直接就是执行失败    QSqlDatabase db;    // 打开数据库    auto openDB = [&]() -> bool {        static QString connectName = "heartbeatCheck";        if (QSqlDatabase::contains(connectName)) {            db = QSqlDatabase::database(connectName);        } else {            db = QSqlDatabase::aDDDatabase(m_mapDBTypeDriver.value(m_type), connectName);        }        if (db.isOpen()) {            db.close();        }        db.setHostName(m_param.ip);        db.setPort(m_param.port);        db.setDatabaseName(m_param.dbName);        db.setUserName(m_param.userName);        db.setPassword(m_param.password);        QTime startTime = QTime::currentTime();        if (db.open()) {            QTime endTime = QTime::currentTime();            qDebug() << "数据库打开成功耗时: " << startTime.msecsTo(endTime) << "ms";            return true;        }        QTime endTime = QTime::currentTime();        qDebug() << "数据库打开失败耗时: " << startTime.msecsTo(endTime) << "ms";        m_lastError = QString("数据库打开失败,原因:%1").arg(db.lastError().text());        return false;    };    // 检测数据库是否在线(执行sql操作)    auto checkDBIsOnline = [&db]() -> bool {        QSqlQuery query(db);        QString sql = "select 1";        QTime startTime = QTime::currentTime();        if (query.exec(sql)) {            return true;        }        QTime endTime = QTime::currentTime();        qDebug() << "检测心跳断开耗时:" << startTime.msecsTo(endTime) << "ms";        return false;    };    // 检测IP是否在线    auto checkIpIsOnline = [](const QString & ip) -> bool {        QProcess cmd;        QString command = "";#ifdef Q_OS_WIN        /// -n 要发送的回显请求数        /// -w 等待每次回复的超时时间(毫秒)        command = QString("ping %1 -n 1 -w 1000").arg(ip);#else        /// -s ping发送的字节数        /// -c ping的次数        command = QString("ping -s 1 -c 1 %1").arg(ip);#endif        cmd.start(command);        cmd.waitForFinished(1000 * 1);        QString retStr = cmd.readAll();        if (retStr.indexOf("ttl", 0, Qt::CaseInsensitive) == -1) {            return false;        }        return true;    };    QTimer timerCheckIp;       // 检测IP是否在线定时器    QTimer timerConnectDB;     // 连接数据库定时器    QTimer timerDBHeartbeat;   // 检测数据库心跳定时器    timerCheckIp.setInterval(m_checkIpIsOnlineInterval);    connect(&timerCheckIp, &QTimer::timeout, [&] {        timerCheckIp.stop();        if (checkIpIsOnline(m_param.ip)) {            qDebug() << "连接网络成功,正在连接数据库";            emit signal_connectedNet();            timerConnectDB.start();        } else {            timerCheckIp.start();        }    });    timerConnectDB.setInterval(m_connectDBInterval);    connect(&timerConnectDB, &QTimer::timeout, [&] {        timerConnectDB.stop();        if (checkIpIsOnline(m_param.ip)) {            if (openDB()) {                qDebug() << "连接数据库成功,开始心跳检测";                emit signal_connectedDB();                timerDBHeartbeat.start();            } else {                timerConnectDB.start();            }        } else {            qDebug() << "网络断开,正在重连";            emit signal_disconnectedNet();            timerCheckIp.start();        }    });    timerDBHeartbeat.setInterval(m_checkDBHeartbeatInterval);    connect(&timerDBHeartbeat, &QTimer::timeout, [&] {        static int checkIpFailTime = 0;        static int checkDBFailTime = 0;        timerDBHeartbeat.stop();        if (checkIpIsOnline(m_param.ip)) {            checkIpFailTime = 0;            if (checkDBIsOnline()) {                checkDBFailTime = 0;                timerDBHeartbeat.start();            } else {                ++checkDBFailTime;                if (checkDBFailTime == kCheckDBFailTime) {                    checkDBFailTime = 0;                    qDebug() << "数据库断开,正在重连";                    emit signal_disconnectedDB();                    timerConnectDB.start();                } else {                    timerDBHeartbeat.start();                }            }        } else {            ++checkIpFailTime;            if (checkIpFailTime == kCheckIpFailTime) {                checkIpFailTime = 0;                qDebug() << "网络断开,正在重连";                emit signal_disconnectedNet();                timerCheckIp.start();            } else {                timerDBHeartbeat.start();            }        }    });    timerCheckIp.start();    qDebug() << "正在连接网络";    exec();}

来源地址:https://blog.csdn.net/lin786063594/article/details/129796554

您可能感兴趣的文档:

--结束END--

本文标题: QT实现检测MySQL数据库连接状态并断开重连

本文链接: https://www.lsjlt.com/news/376431.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作