添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

在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)其他线程则创建自己的连接来执行相应的业务;并可根据子线程检测的状态结果来做相应的判断。
如果有别的方法,还请大佬们指导一下

#ifndef DBHEARTBEATTHREAD_H
#define DBHEARTBEATTHREAD_H
#include <QObject>
#include <QThread>
#include <QMap>
class DBHeartbeatThread : public QThread
    Q_OBJECT
public:
    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 <QDebug>
#include <QSqlError>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QTimer>
#include <QDateTime>
#include <QProcess>
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();
                    在QT中做有关于MySQL的业务时,有时候需要知道MySQL数据库的当前连接状态。但QT在提供的QSqlDatabase模块中并没有相关的功能,不像QTcpSocket在连接服务或断开服务时都有相应的信号发出。
				
//连接数据库bool scoreWindow::createConnection() QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL"); db.setHostName("localhost"); db.setDatabaseName("test");//数据库的名称 db.setUserName("roo
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "a"); db.setConnectOptions("MYSQL_OPT_RECONNECT=1");
PyQt 有内置的数据库连接QtSql 。 在使用 PyQt 连接 MySql 展示数据时,如果明确所有数据库操作都与 Qt 窗口有关,且不涉及复杂的数据操作,则可以使用内置的 QtSql 类。不需要安装额外的数据库类,且能更加便利的与 QtTableView 等 Qt 控件进行数据交互。 db = QtSql.QSqlDatabase.addDatabase('QMYSQL') db.setHostName('localhost') db.setDatabaseName('dev') db.setUserName('root') db.setPassword('123') 1. 调用addDatabase();函数:确定你要连接数据库驱动。我这里用的是Oracle数据库所以是“QOCI”,使用mysql数据库的话自然是"QMYSQL"等等,要选择自己数据库对应的驱动。 2. 调用setHostName();函数:数据库的ip地址,当然如果是你自...
QSqlDatabase:可以提供默认连接Qt其他的SQL类使用。 第一次.据库的连接 用到QSqlDatabase 以及其类中的:: database和 addDatabase, QString g_sThreadId; QSqlDatabase db = QSqlDatabase::database(g_sThreadId); if (! db.isValid()) { // 参数1为驱动名,参数2名连
1、关于UDP的基础信息 UDP(user datagram protocol,用户数据报协议)是轻量的、不可靠的、面向数据报(datagram)、无连接的协议,它可以用于对可靠性要求不高的场合。与TCP通信不同,两个程序之间进行UDP通信无需预先建立持久的socket连接,UDP每次发送数据报都需要指定目标地址和端口。 UDP通信相对于TCP通信的实现来说就稍微容易一些了,因为UDP是不需要分客户端和服务器的。只需要用到一个类QUdpSocket。 UDP消息传送有单播、广播、组播三种模式。 单播(un
Qt实现 TCP 连接失败连和断开连,可以通过以下步骤实现: 1. 创建一个 `QTcpSocket` 实例,并连接 `error(QAbstractSocket::SocketError)` 信号和 `disconnected()` 信号。 ```cpp QTcpSocket *socket = new QTcpSocket(this); connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError))); connect(socket, SIGNAL(disconnected()), this, SLOT(onDisconnected())); 2. 在 `onError(QAbstractSocket::SocketError)` 槽函数中实现连逻辑。当连接出现错误时,可以通过调用 `QTcpSocket::state()` 函数来获取当前连接状态。 ```cpp void MyServer::onError(QAbstractSocket::SocketError error) if (socket->state() == QAbstractSocket::UnconnectedState) { socket->connectToHost("127.0.0.1", 12345); // 连 3. 在 `onDisconnected()` 槽函数中实现断开连逻辑。当连接断开时,可以通过调用 `QTcpSocket::state()` 函数来获取当前连接状态。 ```cpp void MyServer::onDisconnected() if (socket->state() == QAbstractSocket::UnconnectedState) { socket->connectToHost("127.0.0.1", 12345); // 断开连 通过以上步骤,就可以在 Qt实现 TCP 连接失败连和断开连的功能了。