黄色在线观看亚洲,国产在线a不卡无弹窗,影视高清少妇亚洲,亚洲人妻在线视频网,亚洲毛片网

返回列表
基于C++語言實現Qt框架下的數據庫連接池應用

基于C++語言實現Qt框架下的數據庫連接池應用

隨著互聯網和大數據時代的到來,數據庫操作已經成為許多企業和應用程序不可或缺的重要部分。數據庫連接池技術的應用,可以提高數據庫使用效率,減少資源和時間的浪費。基于C++語言的Qt框架,也可以實現數據庫連接池技術,本文將介紹如何使用Qt實現數據庫連接池,讓你的數據庫操作更加高效。

一、什么是數據庫連接池

數據庫連接池是一種通過預先建立多個數據庫連接,在應用程序的運行過程中重復利用數據庫連接的技術。通俗的說,就是在應用程序中預先建立多個數據庫連接,當需要訪問數據庫時從連接池中獲取一個數據庫連接,用完后還回連接池中。這種利用池化技術的方式能夠降低新建連接的時間和資源消耗,提高數據庫的操作效率。下面,我們將使用Qt實現數據庫連接池。

二、Qt中數據庫連接的建立與使用

在Qt中,數據庫連接的建立與使用非常簡單。首先需要創建一個QSqlDatabase實例,在該實例中設置需要連接的數據庫類型、主機和用戶名等信息。然后,使用QSqlDatabase::open()函數打開該數據庫連接,并進行一些操作。

#include <QSqlDatabase >

#include <QSqlQuery>

#include <QDebug>

QSqlDatabase db = QSqlDatabase::addDatabase(“QMYSQL”);

db.setHostName(“localhost”);

db.setDatabaseName(“test”);

db.setUserName(“root”);

db.setPassword(“password”);

if(db.open())

{

qDebug() << “Open database success !”;

QSqlQuery query(db);

query.exec(“select * from testDB”);

while(query.next())

qDebug() << query.value(0).toString();

}

上述代碼演示了在Qt中連接MySQL數據庫的過程。首先使用QSqlDatabase::addDatabase(“QMYSQL”)函數創建一個QSqlDatabase實例,在該實例中設置需要連接的數據庫類型、主機和用戶名等信息。然后,使用QSqlDatabase::open()函數打開該數據庫連接。在數據庫連接成功后,使用QSqlQuery實例進行一些操作。注意,一定要在使用完QSqlQuery對象后,調用其~QSqlQuery()函數釋放資源。

三、Qt實現數據庫連接池

下面,我們將基于Qt實現一個簡單的數據庫連接池。創建一個ConnectionPool類,該類中包含了多個數據庫連接對象。ConnectionPool的.h文件內容如下:

#ifndef CONNECTIONPOOL_H

#define CONNECTIONPOOL_H

#include <QtSql>

#include <QQueue>

#include <QString>

#include <QMutex>

#include <QMutexLocker>

#include<QDebug>

#include<QSettings>//配置文件

class ConnectionPool {

public:

    static void release();                                // 關閉所有的數據庫連接

    static QSqlDatabase openConnection();                 // 獲取數據庫連接

    static void closeConnection(QSqlDatabase connection); // 釋放數據庫連接回連接池

    ~ConnectionPool();

private:

    static ConnectionPool& getInstance();

    ConnectionPool();

    ConnectionPool(const ConnectionPool &other);

    ConnectionPool& operator=(const ConnectionPool &other);

    QSqlDatabase createConnection(const QString &connectionName); // 創建數據庫連接

    QQueue<QString> usedConnectionNames;   // 已使用的數據庫連接名

    QQueue<QString> unusedConnectionNames; // 未使用的數據庫連接名

    // 數據庫信息

    QString hostName;

    QString databaseName;

    QString username;

    QString password;

    QString databaseType;

    bool    testOnBorrow;    // 取得連接的時候驗證連接是否有效

    QString testOnBorrowSql; // 測試訪問數據庫的 SQL

    int maxWaitTime;         // 獲取連接最大等待時間

    int waitInterval;        // 嘗試獲取連接時等待間隔時間

    int maxConnectionCount;  // 最大連接數

    static QMutex mutex;

    static QWaitCondition waitConnection;

    static ConnectionPool *instance;

};

#endif // CONNECTIONPOOL

SqlDatabase是Qt框架中操作數據庫的重要類之一,可以通過該類實現數據庫連接的建立和操作。ConnectionPool類是自定義的一個庫連接池類,在該類中定義了數據庫連接的各種屬性,并包含了多個數據庫連接對象。

在ConnectionPool類的實現文件中,我們將實現具體的方法。定義如下靜態變量:

QMutex ConnectionPool::mutex;

QWaitCondition ConnectionPool::waitConnection;

ConnectionPool* ConnectionPool::instance = nullptr;

用靜態變量ConnectionPool::instance來存儲ConnectionPool類的唯一實例,同時使用QMutex和QWaitCondition分別保護多線程的同步和條件變量的使用。

接著,實現單態模式中的getInstance()方法。該方法用于返回ConnectionPool類的唯一實例:

ConnectionPool& ConnectionPool::getInstance() {

    if (nullptr == instance) {

        QMutexLocker locker(&mutex);

        if (nullptr == instance) {

            instance = new ConnectionPool();

        }

    }

    return *instance;

}

在getInstance ()方法中,使用互斥鎖QMutexLocker保證了多線程同步,使用雙重檢查鎖定機制確保了ConnectionPool類的唯一實例。

然后,我們可以實現如下連接的建立與關閉方法openConnection()和closeConnection()。openConnection()方法用于從連接池中獲取一個數據庫連接,closeConnection()方法用于還回這個數據庫連接:

QSqlDatabase ConnectionPool::openConnection() {

    ConnectionPool& pool = ConnectionPool::getInstance();

    QString connectionName;

    QMutexLocker locker(&mutex);

    // 已創建連接數

    int connectionCount = pool.unusedConnectionNames.size() + pool.usedConnectionNames.size();

    // 如果連接已經用完,等待 waitInterval 毫秒看看是否有可用連接,最長等待 maxWaitTime 毫秒

    for (int i = 0;

         i < pool.maxWaitTime

         && pool.unusedConnectionNames.size() == 0 && connectionCount == pool.maxConnectionCount;

         i += pool.waitInterval) {

        waitConnection.wait(&mutex, pool.waitInterval);

        // 重新計算已創建連接數

        connectionCount = pool.unusedConnectionNames.size() + pool.usedConnectionNames.size();

    }

    if (pool.unusedConnectionNames.size() > 0) {

        // 有已經回收的連接,復用它們

        connectionName = pool.unusedConnectionNames.dequeue();

    } else if (connectionCount < pool.maxConnectionCount) {

        // 沒有已經回收的連接,但是沒有達到最大連接數,則創建新的連接

        connectionName = QString("Connection-%1").arg(connectionCount + 1);

    } else {

        // 已經達到最大連接數

        qDebug() << "Cannot create more connections.";

        return QSqlDatabase();

    }

    // 創建連接

    QSqlDatabase db = pool.createConnection(connectionName);

    // 有效的連接才放入 usedConnectionNames

    if (db.isOpen()) {

        pool.usedConnectionNames.enqueue(connectionName);

    }

    return db;

}

void ConnectionPool::closeConnection(QSqlDatabase connection) {

    ConnectionPool& pool = ConnectionPool::getInstance();

    QString connectionName = connection.connectionName();

    // 如果是我們創建的連接,從 used 里刪除,放入 unused 里

    if (pool.usedConnectionNames.contains(connectionName)) {

        QMutexLocker locker(&mutex);

        pool.usedConnectionNames.removeOne(connectionName);

        pool.unusedConnectionNames.enqueue(connectionName);

        waitConnection.wakeOne();

    }

}

在openConnection()方法中,首先獲取互斥鎖QMutexLock,在連接池中查找是否有空閑連接。如果有,直接返回該連接,否則查看可用的連接數是否達到上限,如果沒有,則創建新的連接。當新連接創建成功后,檢查該連接是否打開,如果打開,則更新連接數。最后釋放互斥鎖。

closeConnection()方法用于還回連接到連接池中,并檢查連接池中連接數量是否超過設定的更大值,如果超過,則移除最早的連接。程序執行完該方法后,也應該釋放互斥鎖。

我們實現ConnectionPool的構造函數和析構函數:

ConnectionPool::ConnectionPool() {

    hostName     = "127.0.0.1";//主機名

    databaseName = "DRIVER={SQL SERVER};SERVER=127.0.0.1;DATABASE=testDB";//需要訪問的數據庫

    username     = "sa";      //用戶名

    password     = "123456";  //密碼

    databaseType = "QODBC";   //數據庫類型

    testOnBorrow = true;

    testOnBorrowSql = "SELECT 1";

    maxWaitTime  = 1000;

    waitInterval = 200;

    maxConnectionCount  = 1000;

}

ConnectionPool::~ConnectionPool() {

    // 銷毀連接池的時候刪除所有的連接

    foreach(QString connectionName, usedConnectionNames) {

        QSqlDatabase::removeDatabase(connectionName);

    }

    foreach(QString connectionName, unusedConnectionNames) {

        QSqlDatabase::removeDatabase(connectionName);

    }

}

void ConnectionPool::release() {

    QMutexLocker locker(&mutex);

    delete instance;

    instance = nullptr;

}

QSqlDatabase ConnectionPool::createConnection(const QString &connectionName) {

    // 連接已經創建過了,復用它,而不是重新創建

    if (QSqlDatabase::contains(connectionName)) {

        QSqlDatabase db1 = QSqlDatabase::database(connectionName);

        if (testOnBorrow) {

            // 返回連接前訪問數據庫,如果連接斷開,重新建立連接

            qDebug() << "Test connection on borrow, execute:" << testOnBorrowSql << ", for" << connectionName;

            QSqlQuery query(testOnBorrowSql, db1);

            if (query.lastError().type() != QSqlError::NoError && !db1.open()) {

                qDebug() << "Open datatabase error:" << db1.lastError().text();

                return QSqlDatabase();

            }

        }

        return db1;

    }

    // 創建一個新的連接  注意:如果需要跨線程操作時這里需要連接時需要設置個靜態連接數據庫

    QSqlDatabase db = QSqlDatabase::addDatabase(databaseType, connectionName);

    db.setHostName(hostName);

    db.setDatabaseName(databaseName);

    db.setUserName(username);

    db.setPassword(password);

    db.setPort(3306);

    if (!db.open()) {

        qDebug() << "Open datatabase error:" << db.lastError().text();

        return QSqlDatabase();

    }

    return db;

}

在ConnectionPool類的構造函數中,預先創建maxConnectionCount個數據庫連接,并存儲在usedConnectionNames中。在該構造函數調用后,用戶可以直接通過openConnection()方法獲取連接,加快數據庫操作的速度。

數據庫連接長時間不操作是可能會斷開,檢查數據庫的配置連接時間,一般會有時間限制,建議你程序啟動需要和數據庫交互時,先判斷數據庫是否是連接狀態,未連接時重新連接。

關于qt中數據庫連接池的介紹到此就結束了。


如有侵權,聯系刪除。

網站編輯:小優智能科技有限公司 發布時間:Nov 08,2023
給我們留言
驗證碼