Qt多线程连接数据库

原理

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。

而其实质上连接池就是通过单例,在进行工具类调用连接后通过一个集合来建立几个连接对象。在进行连接的时候来通过集合分配对象,采用对象锁来限制多线程的资源抢夺情况。

一、头文件

#ifndef CSQLDATABASE_H
#define CSQLDATABASE_H

#include <QtSql>
#include <QString>
#include <QMutex>
#include <QMutexLocker>
#include <QWaitCondition>
#include <QQueue>
/*
 * qt时间样式
 * 年月:yyyy-mm-dd
 * 时间:hh24:mi:ss
 * 年月时间:yyyy-mm-dd hh24:mi:ss
 */


class CSQLDatabase
{
public:
    /*
     * 单例模式获取
     * 参数:ip,用户名,用户密码,数据库名,数据库类型,端口号,最大连接数,最长等待时间,等待间隔
     */
    static CSQLDatabase& GetInstance(QString qsHostName, QString qsUser, QString qsPassWd,
                                     QString qsDatabase, QString qsDatabaseType, int nPort,
                                     int nMaxConn, int nMaxWaitTime, int nWaitInter);

    bool                ExecuteStmt(QString qsSql); //用于增删改
    QSqlQuery           ExecuteQuery(QString qsSql);//用于查询

    ~CSQLDatabase();

private:
    CSQLDatabase(QString qsHostName, QString qsUser, QString qsPassWd,
                 QString qsDatabase, QString qsDatabaseType, int nPort,
                 int nMaxConn, int nMaxWaitTime, int nWaitInter);

    QSqlDatabase    OpenConnection();
    void            CloseConnection(QSqlDatabase connection);
    QSqlDatabase    CreateConnect(const QString& qsConnName);

private:
    int m_nPort;
    int m_nMaxConn;
    int m_nMaxWaitTime; //最长等待时间
    int m_nWaitInter;   //等待间隔

    QString m_qsHostName;
    QString m_qsUser;
    QString m_qsPassWd;
    QString m_qsDatabase;
    QString m_qsDatabaseType;


    QQueue<QString> m_queUseConnNames;
    QQueue<QString> m_queUnuserConnNames;

    static QMutex m_Mutex;
    static QWaitCondition m_WaitConn;
    static CSQLDatabase* m_pInstance;
};

static CSQLDatabase glSqlDatabse = CSQLDatabase::GetInstance("127.0.0.1", "aaron", "0", "db", "QOCI", 1521, 5, 10, 1);

#endif // CSQLDATABASE_H

二、源文件

#include "CSQLDatabase.h"

QMutex CSQLDatabase::m_Mutex;
CSQLDatabase* CSQLDatabase::m_pInstance = nullptr;
QWaitCondition CSQLDatabase::m_WaitConn;

CSQLDatabase& CSQLDatabase::GetInstance(QString qsHostName, QString qsUser, QString qsPassWd,
                                 QString qsDatabase, QString qsDatabaseType, int nPort,
                                 int nMaxConn, int nMaxWaitTime, int nWaitInter)
{
    if(m_pInstance == nullptr)
    {
        QMutexLocker locker(&m_Mutex);
        m_pInstance = new CSQLDatabase(qsHostName, qsUser, qsPassWd, qsDatabase,
                                       qsDatabaseType, nPort, nMaxConn, nMaxWaitTime, nWaitInter);
    }

    return *m_pInstance;
}

CSQLDatabase::CSQLDatabase(QString qsHostName, QString qsUser, QString qsPassWd,
                           QString qsDatabase, QString qsDatabaseType, int nPort,
                           int nMaxConn, int nMaxWaitTime, int nWaitInter)
    :m_qsHostName(qsHostName), m_qsUser(qsUser), m_qsPassWd(qsPassWd), m_qsDatabase(qsDatabase),
      m_qsDatabaseType(qsDatabaseType), m_nPort(nPort), m_nMaxConn(nMaxConn),
      m_nMaxWaitTime(nMaxWaitTime), m_nWaitInter(nWaitInter)
{
}

CSQLDatabase::~CSQLDatabase()
{
    QMutexLocker locker(&m_Mutex);
    foreach(QString connName, m_pInstance->m_queUseConnNames)   //移除所有使用中的连接
        QSqlDatabase::removeDatabase(connName);

    foreach(QString unConnName, m_pInstance->m_queUnuserConnNames)  //移除所有未使用的连接
        QSqlDatabase::removeDatabase(unConnName);

    m_pInstance = nullptr;
}

QSqlDatabase CSQLDatabase::OpenConnection()
{
    QMutexLocker locker(&m_Mutex);
    QString qsConnName;

    int nCountT = m_queUseConnNames.size() + m_queUnuserConnNames.size();
    //如果未到等待时间,并且所有的连接都在使用中,根据等待间隔进入到等待
    for(int i = 0; i < m_nMaxWaitTime && m_queUnuserConnNames.size() == 0 && nCountT == m_queUseConnNames.size(); i += m_nWaitInter)
    {
        //进行等待
        m_WaitConn.wait(&m_Mutex, m_nWaitInter);
        //重新计数总连接
        nCountT = m_queUseConnNames.size() + m_queUnuserConnNames.size();
    }

    //判断是否需要创建新连接,使用未使用连接,或者在连接全在使用时返回空的连接(可自己修改)
    if(m_queUnuserConnNames.size() > 0)
        qsConnName = m_queUnuserConnNames.dequeue();
    else if(nCountT < m_nMaxConn)
        qsConnName = QString("Connection-%1").arg(nCountT + 1);
    else {
        qDebug() << "All use sql connect";
        return QSqlDatabase();
    }

    //创建新连接,并放入到正在使用的连接容器中
    QSqlDatabase db = CreateConnect(qsConnName);
    if(db.isOpen())
        m_queUseConnNames.enqueue(qsConnName);

    return db;
}

void CSQLDatabase::CloseConnection(QSqlDatabase connection)
{
    //关闭连接,并将连接名放回未连接容器中
    QMutexLocker locker(&m_Mutex);
    QString qsConnName = connection.connectionName();
    if(m_queUseConnNames.contains(qsConnName))
    {
        m_queUseConnNames.removeOne(qsConnName);
        m_queUnuserConnNames.enqueue(qsConnName);
        //如果某一线程已使用完连接,另一线程正在申请一个数据库连接,进行唤醒操作
        m_WaitConn.wakeOne();
    }
}

QSqlDatabase CSQLDatabase::CreateConnect(const QString &qsConnName)
{
    //查看该连接名是否已经创建过连接
    if(QSqlDatabase::contains(qsConnName))
    {
        QSqlDatabase db = QSqlDatabase::database(qsConnName);
        return db;
    }

    QSqlDatabase db = QSqlDatabase::addDatabase(m_qsDatabaseType, qsConnName);
    db.setHostName(m_qsHostName);
    db.setDatabaseName(m_qsDatabase);
    db.setUserName(m_qsUser);
    db.setPassword(m_qsPassWd);
    db.setPort(m_nPort);

    if(!db.open())
    {
        qDebug() << "Open sql error" << db.lastError().text();
        return QSqlDatabase();
    }

    return db;
}

bool CSQLDatabase::ExecuteStmt(QString qsSql)
{
    QSqlDatabase db = OpenConnection();
    if(!db.isOpen())
        return false;

    QSqlQuery query = db.exec(qsSql);
    CloseConnection(db);

    if(query.lastError().isValid())
    {
        qDebug() << "Sql error:" << query.lastError();
        return false;
    }

    return true;
}

QSqlQuery CSQLDatabase::ExecuteQuery(QString qsSql)
{
    QSqlDatabase db = OpenConnection();
    if(!db.isOpen())
        return QSqlQuery();

    QSqlQuery query = db.exec(qsSql);
    CloseConnection(db);

    if(query.lastError().isValid())
    {
        qDebug() << "Sql error:" << query.lastError();
        return QSqlQuery();
    }

    return query;
}


本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,C++设计模式,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

猜你喜欢

转载自blog.csdn.net/m0_73443478/article/details/130953354