Qt+數據庫


前言支持內置數據庫:

驅動關系:

拿Mysql舉例,我們的Qt程序有自己的驅動,libqsqlmysql.dll,如果Qt安裝好了之后沒有這個動態庫,則需要自己使用qmake編譯。如果有了這個驅動,說明我們的Qt環境已經ok了,但是如果需要訪問Mysql數據庫,還需要Mysql提供的訪問它的驅動libmysql.dll【linux對應libmysqlclient.so.18,不同mysql版本名字不一樣】。總結就是:Qt程序->libqsqlmysql.dll->libmysql.dll->Mysql數據庫

libqsqlmysql.dll:安裝Qt附帶或者源代碼編譯

libmysql.dll:安裝mysql或者直接網上找這個動態庫

一、sqlite

1、在頭文件中聲明數據庫對象

QSqlDatabase db;

2、在構造函數中定義對象(最好這樣定義,因為對於db來說只需要addDatabase一次,否則多次addDatabase會報錯)

if(QSqlDatabase::contains("qt_sql_default_connection"))

  db = QSqlDatabase::database("qt_sql_default_connection");

else

  db = QSqlDatabase::addDatabase("QSQLITE");

3、設置數據庫文件路徑

db.setDatabaseName(".//qtDb.db");//設置數據庫文件名字,選擇的是當前路徑

4、打開數據庫

if(!db.open())

{

  qDebug() << "打開數據庫失敗";

  return;

}

5、判斷數據庫中是否存在某表,不存在則新建(數據庫指令相關)

QSqlQuery query(db);

bool isTableExist = query.exec("select * from CSSBDB");//關鍵的判斷

if(!isTableExist)//表不存在,新建表

{

  bool success = query.exec("create table CSSBDB(id INTEGER PRIMARY KEY,設備名稱 varchar,設備型號 varchar,固定資產編號 varchar,測試部自編號 varchar,卡片編號 varchar,數量 varchar,單價 varchar,啟用時間 varchar,用途 varchar,使用人或保管人 varchar,備注 varchar)");//創建數據表

  if(success)

  {

    qDebug() <<"數據庫表1創建成功!";

  }

  else

  {

      qDebug() <<"數據庫表1創建失敗!";

      QSqlError tempErr = query.lastError();

      qDebug()<<tempErr;

      return;

  }

}

6、獲取數據庫中有多少數據(行數和列數)

query.exec("select * from CSSBDB");

QSqlQueryModel *model = new QSqlQueryModel();

model->setQuery(query);

int nRecordCount = model->rowCount();//行數

int nColumnCount = model->columnCount();//列數

7、獲取表的表頭內容

if(query.exec("PRAGMA table_info(CSSBDB)"))

{

QStringList tempList;

while(query.next())

  {

  tempList.append(query.value(1).toString());

  }

}

下圖是獲取表信息結果

8、更新某條記錄

update CSSBDB set companyNumber='050689' where id=2

9、插入一條記錄

insert into CSSBDB values(null,"台式主機","DELL9020MT","050688","CSB-PC001-A","123","1","3000","2016.4.15","服務器","","")//如果id是null則表示id按順序增加1

10、關閉數據庫

db.close();

 

 

二、Access

{
        QSqlDatabase db = QSqlDatabase::addDatabase("QODBC", "EXPORT_EXCEL");
        QString dsn = QString("DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};FIL={MS Access};DBQ=%1").arg(filePath);// DB_PATH
        db.setDatabaseName(dsn);//設置數據庫路徑

        QString sqlStr;
        if (!db.open())
        {
            qDebug() << "打開數據庫失敗";
        }
        else
        {
            QSqlQuery query(db);
            sqlStr = "";
            sqlStr = QString("SELECT *  FROM tableName");
            query.exec(sqlStr);
        } 
} QSqlDatabase::removeDatabase(
"EXPORT_EXCEL");

 

 

ps:

1、query.next(數據庫命令)是每次返回一行數據,要取出當前行的某列數據,使用query.value(n),n從0開始

2、判斷當前qt可用的數據庫驅動

QStringList drivers = QSqlDatabase::drivers();
foreach(QString driver, drivers)
qDebug() << "\t" << driver;

QSqlDatabase db = QSqlDatabase::addDatabase("QODBC", "test");
qDebug() << "ODBC driver valid?" << db.isValid();

 3、query.exec,如果sql語句沒錯,拿它是不會報錯的,即時返回值為空,它也沒錯

4、數據庫回收

 

{

  //這里用{}畫出一個作用域,當這個域完成之后,數據庫的所有操作動作都被回收了
  QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");//數據庫,設置為Access2000
  QString dsn = QString("DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};FIL={MS Access};DBQ=%1").arg(DB_PATH);//這是access的數據庫,需要與當前電腦數據庫驅動一致:控制面板,數據源,ODBC
  db.setDatabaseName(dsn);//設置數據庫路徑
  db.open();

  //數據庫操作

}
QSqlDatabase::removeDatabase("qt_sql_default_connection");//這句話之前保證當前連接的數據庫沒有任何數據操作,由上面的作用域實現

5、數據庫原理:

QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");

上面這句話是新建一個連接,每個連接是對數據庫的唯一標識,如果像上面這樣寫,連接名稱就是默認的qt_sql_default_connection,最后回收的時候也是QSqlDatabase::removeDatabase("qt_sql_default_connection")

如果在程序中多個地方【線程】操作數據庫:QSqlDatabase db = QSqlDatabase::addDatabase("QODBC","MyConnction");

回收:QSqlDatabase::removeDatabase("MyConnction");

6、有時候出現問題:"[Microsoft][ODBC 驅動程序管理器] 未發現數據源名稱並且未指定默認驅動程序 QODBC3: Unable to connect" 

  1、dsn語句有誤

  2、數據庫驅動不正確,當時我編譯的是64位的,正常運行,后來改成了32位的,報上面錯,下載32位的驅動安裝了就ok了

7、解決通過model->rowCount();只能返回最多256個數據

   while(model->canFetchMore())  

   {  

        model->fetchMore();  

   }  

8、使用了數據庫時,有時打包軟件出現“driver not load”

1)將C:\Qt\Qt5.3.1\5.3\msvc2012路徑下的文件夾plugins復制到exe文件目錄下,打開plugins,只保留sqldrivers文件夾,需要確認里面是否有你需要的驅動, 如:程序中使用了QSqlite數據庫,則需要有qsqlite.dll(發布版)qsqlited.dll(調試版),

2)在main.cpp文件中添加下面第二行和第三行:

  QApplication a(argc, argv);   
QString strLibPath(QDir::toNativeSeparators(QApplication::applicationDirPath())+QDir::separator()+"plugins");
a.addLibraryPath(strLibPath);

9、將數據庫快速轉Excel的辦法

sqlStr = "SELECT * INTO [excel 8.0;database=.\\Data\\export\\1.xls].Sheet1 FROM tableName";

三、mysql

3.1、自己封裝的單次訪問數據庫類,自動實現釋放連接

頭文件:

#ifndef MYSQLTOOL_H
#define MYSQLTOOL_H #include <QSqlDatabase> #include "includes.h" #include <QSqlQuery> #include <mutex> class Mysqltool { public: Mysqltool(QString dataBaseName); virtual ~Mysqltool(); public: bool exec(QString sql);//插入、刪除、更新 bool select(QString sql,QSqlQuery& rsltQuery);//查詢 private: QSqlDatabase* pDb; QString dataBaseName; void setRandString(QString & randString);//獲取隨機字符串 }; extern std::mutex m_mutext_opensql; #endif // MYSQLTOOL_H

源文件:

#include "mysqltool.h"
#include "mymethod.h" #include <QSqlError> #include <QTime> std::mutex m_mutext_opensql; /*****************************************************************/ //作者:朱小勇 //函數名稱:構造函數 //函數參數:NULL //函數返回值:NULL //函數作用:NULL //備注:NULL /*****************************************************************/ Mysqltool::Mysqltool(QString dataBaseName) { QString randStr;setRandString(randStr); dataBaseName += randStr; #if CLOSE_IF Mymethod::record(dataBaseName); #endif pDb = new QSqlDatabase(QSqlDatabase::addDatabase("QMYSQL", dataBaseName)); pDb->setHostName(DB_IP); //ip pDb->setUserName(DB_USER_NAME); //登陸MYSQL的用戶名 pDb->setPassword(DB_PASSWORD); //登陸的密碼 pDb->setDatabaseName(DB_DATABASE_NAME); //數據庫的名稱 m_mutext_opensql.lock(); if(!pDb->open()) { Mymethod::record("數據庫打開失敗:"); // QSqlError tempErr = db.lastError(); // qDebug()<<tempErr;  } m_mutext_opensql.unlock(); this->dataBaseName = dataBaseName; } /*****************************************************************/ //作者:朱小勇 //函數名稱:析構函數 //函數參數:NULL //函數返回值:NULL //函數作用:NULL //備注:NULL /*****************************************************************/ Mysqltool::~Mysqltool() { pDb->close(); delete pDb; pDb = nullptr; QSqlDatabase::removeDatabase(dataBaseName); } /*****************************************************************/ //作者:朱小勇 //函數名稱:增刪改 //函數參數:NULL //函數返回值:NULL //函數作用:NULL //備注:NULL /*****************************************************************/ bool Mysqltool::exec(QString sql) { bool ret = true; RET_VALUE_IF_EAQU(pDb->isOpen(),false,false); QSqlQuery query(*pDb); #if OPEN_IF if(!query.exec(sql)) { QSqlError tempErr = query.lastError(); qDebug()<<tempErr; qDebug()<<"sql:"<<sql; } #endif #if CLOSE_IF RET_VALUE_IF_EAQU(query.exec(sql),false,false); #endif return ret; } /*****************************************************************/ //作者:朱小勇 //函數名稱:查 //函數參數:NULL //函數返回值:NULL //函數作用:NULL //備注:如果有問題可以將查詢結果放在堆上 /*****************************************************************/ bool Mysqltool::select(QString sql,QSqlQuery& rsltQuery) { bool ret = true; QSqlQuery query(*pDb); RET_VALUE_IF_EAQU(query.exec(sql),false,false); rsltQuery = query; return ret; } /*****************************************************************/ //作者:朱小勇 //函數名稱:獲取隨機字符串,保證連接名不同 //函數參數:NULL //函數返回值:NULL //函數作用:NULL //備注:NULL /*****************************************************************/ void Mysqltool::setRandString(QString & randString) { int max = 8; QString tmp = QString("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWZYZ"); QString str; QTime t; t= QTime::currentTime(); qsrand(t.msec()+t.second()*1000); for(int i=0;i<max;i++) { int ir = qrand()%tmp.length(); str[i] = tmp.at(ir); } randString = str; }

 注意:在removeDatabase之前要保證數據庫相關的對象都回收了,所以將db設計成指針,如果db是類成員變量,那么removeDatabase的時候db永遠存在,就會失敗。

這是自己封裝的訪問數據庫類,工作原理是每次訪問數據庫都在對應的線程里建立一個連接,並建立db對象,再訪問。缺點是需要每次都建立數據庫,浪費時間和數據庫資源。

下面使用數據庫連接池的方式來封裝【參考網上的】

3.2、網上借鑒的數據庫連接池,問題其實都很多。釋放的時候鎖應該放最上面【原文是先方式互斥體再使用鎖,讓我弄了好久】

ConnectPool.h

#ifndef CONNECTPOOL_H
#define CONNECTPOOL_H

#include <QObject>
#include <QtSql>
#include <QQueue>
#include <QMutex>
#include <QMutexLocker>

class ConnectPool : public QObject
{
    Q_OBJECT

public:
    static void release();  //關閉所有數據庫連接
    static QSqlDatabase openConnection();   //獲取數據庫連接
    static void closeConnection(QSqlDatabase connection); //釋放數據庫連接回連接池

    ~ConnectPool();
public:
    static ConnectPool& getInstance();
private:
    ConnectPool();
    ConnectPool(const ConnectPool &other)=default;
    ConnectPool& operator=(const ConnectPool &other)=default;
    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 ConnectPool *instance;

signals:

public slots:
};

#endif // CONNECTPOOL_H

ConnectPool.cpp

#include "connectpool.h"

QMutex ConnectPool::mutex;
QWaitCondition ConnectPool::waitConnection;
ConnectPool* ConnectPool::instance = nullptr;

ConnectPool::ConnectPool()
{
    hostName = "192.168.1.126";
    databaseName = "source_data";
    username     = "root";
    password     = "zhuxiaoyong1212";
    databaseType = "QMYSQL";

    testOnBorrow = true;
    testOnBorrowSql = "SELTCT 1";

    maxWaitTime = 1000;
    waitInterval = 200;         //嘗試獲取連接時等待間隔時間
    maxConnectionCount = 5;

}

ConnectPool::~ConnectPool()
{
    foreach (QString connectionName, usedConnectionNames) {
        QSqlDatabase::removeDatabase(connectionName);
    }

    foreach (QString connectionName, unusedConnectionNames) {
        QSqlDatabase::removeDatabase(connectionName);
    }
}

ConnectPool &ConnectPool::getInstance()
{
    if(instance==nullptr)
    {
        QMutexLocker locker(&mutex);

        if(nullptr==instance)
        {
            instance = new ConnectPool();
        }
    }

    return *instance;
}

void ConnectPool::release()
{
    QMutexLocker locker(&mutex);
    delete instance;            //調用析構函數
    instance = nullptr;
}

QSqlDatabase ConnectPool::openConnection()
{
    ConnectPool &pool = ConnectPool::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 ConnectPool::closeConnection(QSqlDatabase connection)
{
    ConnectPool &pool = ConnectPool::getInstance();
    QString connectName = connection.connectionName();
QMutexLocker locker(&mutex);//位置別放錯了
//如果是我們創建的連接,從used里刪除,放入unused if(pool.usedConnectionNames.contains(connectName)) { pool.usedConnectionNames.removeOne(connectName); pool.unusedConnectionNames.enqueue(connectName); waitConnection.wakeOne(); } } QSqlDatabase ConnectPool::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 database error:"<<db1.lastError().text(); return QSqlDatabase(); } } return db1; } if(!QSqlDatabase::contains(connectionName)) { QSqlDatabase db = QSqlDatabase::addDatabase(databaseType,connectionName); db.setHostName(hostName); db.setDatabaseName(databaseName); db.setUserName(username); db.setPassword(password); if(!db.open()) { qDebug()<<"Open database error:"<<db.lastError().text(); return QSqlDatabase(); } return db; } }

注意:

1、這里的原理是仿照線程池的原理,用兩個隊列來存使用的和沒使用的數據庫連接名,然后在各自的地方或線程處使用這個連接名。這里有個問題:可能會跨線程調用數據庫連接,注意,經過測試,5.12版本到5.13版本一直不支持這個操作,無奈又退到5.10。看過外帖子,貌似是Qt自己的bug,但是至今2019.09.06沒修復。

2、在使用了Qt5.13版本時,發現Qt根本沒有QMysql驅動,即打印當前可用數據庫驅動沒有MySql【按理說是文章開頭那張表】。

 3.3、自己封裝的數據庫連接池,借鑒了上面的

MyConnection.h

#ifndef MYCONNECTION_H
#define MYCONNECTION_H


#define MYDBP_VALUE_0 0

#include <QDebug>
#include <QSqlDatabase>
#include <QSqlError>
#include <QQueue>
#include <mutex>
#include <condition_variable>
#include "mymethod.h"
#include "includes.h"
class MyConnection
{

public:
    static MyConnection* getInstace();
    static QSqlDatabase getDb();//獲取一個db
    static void removeDb(QSqlDatabase db);//回收一個db
    static void clearAllDb();//清楚所有連接
    void setCfg(DbConfig cfg);
private:
    MyConnection();
    static MyConnection* singleton;
    ~MyConnection();
private://運算相關
    QQueue<QString> freeQueue,busyQueue;//可用連接隊列,繁忙隊列
    static std::mutex m_mutex;
    static std::condition_variable cv;
private://數據庫配置相關
    QString dbIp;
    QString dbName;
    QString userName;
    QString password;
    QString dbType;
    int maxConnectionCount; // 最大連接數
    DbConfig cfg;
};

#endif // MYCONNECTION_H

MyConnection.cpp

#include "myconnection.h"

/*****************************************************************/
//作者:朱小勇
//函數名稱:構造函數
//函數參數:NULL
//函數返回值:NULL
//函數作用:NULL
//備注:NULL
/*****************************************************************/
MyConnection::MyConnection()
{
    Mymethod::record("construct dp connection pool.",PRINT_INFO);
    dbIp = "192.168.1.1";
    dbName = "ea_phm";
    userName = "root";
    password = "zhuxiaoyong1212";
    dbType = "QMYSQL";
    maxConnectionCount = DB_CONNET_COUNT;// 最大連接數
}

/*****************************************************************/
//作者:朱小勇
//函數名稱:數據庫設置
//函數參數:NULL
//函數返回值:NULL
//函數作用:NULL
//備注:NULL
/*****************************************************************/
void MyConnection::setCfg(DbConfig cfg)
{
    dbIp = cfg.hostIp;
    dbName = cfg.databaseName;
    userName = cfg.username;
    password = cfg.password;
    dbType = "QMYSQL";
    Mymethod::record("db connection initialized,database name:"+dbName,PRINT_INFO);
}

/*****************************************************************/
//作者:朱小勇
//函數名稱:析構函數
//函數參數:NULL
//函數返回值:NULL
//函數作用:NULL
//備注:NULL
/*****************************************************************/
MyConnection::~MyConnection()
{
    clearAllDb();
    if(singleton != nullptr)
    {
        delete singleton;
        singleton = nullptr;
    }
}

MyConnection* MyConnection::singleton = new MyConnection();//靜態變量初始化
std::mutex MyConnection::m_mutex;
std::condition_variable MyConnection::cv;
/*****************************************************************/
//作者:朱小勇
//函數名稱:返回單例對象
//函數參數:NULL
//函數返回值:NULL
//函數作用:NULL
//備注:NULL
/*****************************************************************/
MyConnection* MyConnection::getInstace()
{
    return singleton;
}

/*****************************************************************/
//作者:朱小勇
//函數名稱:獲取一個連接
//函數參數:NULL
//函數返回值:NULL
//函數作用:NULL
//備注:NULL
/*****************************************************************/
QSqlDatabase MyConnection::getDb()
{
    std::unique_lock<std::mutex> lck(m_mutex);
    MyConnection* instace =  MyConnection::getInstace();

    int currentConnets = instace->freeQueue.size()+instace->busyQueue.size();
    if(currentConnets < instace->maxConnectionCount)//新建連接
    {
        QSqlDatabase db = QSqlDatabase::addDatabase(instace->dbType,QString("connet_num_%1").arg(currentConnets));
        db.setHostName(instace->dbIp);
        db.setDatabaseName(instace->dbName);
        db.setUserName(instace->userName);
        db.setPassword(instace->password);
        if(!db.open())
        {
            QSqlError tempErr = db.lastError();
            Mymethod::record(tempErr.text(),PRINT_ERR);
            return QSqlDatabase();
        }
        if(db.isValid()&&db.isOpen())
        {
            instace->busyQueue.push_back(db.connectionName());
            return db;
        }
    }

    if(instace->freeQueue.size() > MYDBP_VALUE_0)//有空閑的連接直接使用
    {
        QSqlDatabase db = QSqlDatabase::database(instace->freeQueue.front());
        db.setHostName(instace->dbIp);
        db.setDatabaseName(instace->dbName);
        db.setUserName(instace->userName);
        db.setPassword(instace->password);
        if(!db.open())
        {
            QSqlError tempErr = db.lastError();
            Mymethod::record(tempErr.text(),PRINT_ERR);
            return QSqlDatabase();
        }
        if(db.isValid()&&db.isOpen())
        {
            instace->busyQueue.push_back(db.connectionName());//存入繁忙隊列
            instace->freeQueue.pop_front();//從空閑隊列刪除
            return db;
        }
    }

    if((instace->freeQueue.size()==MYDBP_VALUE_0)&&(instace->busyQueue.size()==instace->maxConnectionCount))//無空閑的連接,等待外部釋放
    {
        Mymethod::record(QString("cannot create more connections,used db connection:%1,unused db connection:%2").arg(instace->busyQueue.size()).arg(instace->freeQueue.size()),PRINT_ERR);
        while(instace->freeQueue.size()==MYDBP_VALUE_0)
        {
            cv.wait(lck);
        }
        QSqlDatabase db = QSqlDatabase::addDatabase(instace->dbType,instace->freeQueue.front());
        db.setHostName(instace->dbIp);
        db.setDatabaseName(instace->dbName);
        db.setUserName(instace->userName);
        db.setPassword(instace->password);
        if(!db.open())
        {
            QSqlError tempErr = db.lastError();
            Mymethod::record(tempErr.text(),PRINT_ERR);
            return QSqlDatabase();
        }
        if(db.isValid()&&db.isOpen())
        {
            instace->busyQueue.push_back(db.connectionName());//存入繁忙隊列
            instace->freeQueue.pop_front();//從空閑隊列刪除
            return db;
        }
    }
    return QSqlDatabase();
}

/*****************************************************************/
//作者:朱小勇
//函數名稱:刪除連接
//函數參數:NULL
//函數返回值:NULL
//函數作用:NULL
//備注:NULL
/*****************************************************************/
void MyConnection::removeDb(QSqlDatabase db)
{
    std::unique_lock<std::mutex> lck(m_mutex);
    MyConnection* instace =  MyConnection::getInstace();
    if(instace->busyQueue.contains(db.connectionName()))
    {
        instace->busyQueue.removeOne(db.connectionName());
        instace->freeQueue.push_back(db.connectionName());
    }
    cv.notify_one();
}

/*****************************************************************/
//作者:朱小勇
//函數名稱:清除所有連接
//函數參數:NULL
//函數返回值:NULL
//函數作用:NULL
//備注:NULL
/*****************************************************************/
void MyConnection::clearAllDb()
{
    std::unique_lock<std::mutex> lck(m_mutex);
    MyConnection* instace =  MyConnection::getInstace();
    for(auto connct : instace->freeQueue)
    {
        QSqlDatabase::removeDatabase(connct);
    }
    for(auto connct : instace->busyQueue)
    {
        QSqlDatabase::removeDatabase(connct);
    }
}

我自己封裝這個相比於網上廣為流傳的,少了等待操作。所以當外部向這個單例類請求獲取db后,如果返回的是空db,應該再外面自行等待

     QSqlDatabase db = MyConnection::getDb();
        while(!db.isValid() || !db.isOpen())
        {
            Mymethod::record("db is invalid,retry to get a valid db.",PRINT_ERR);
            QThread::msleep(VALUE_300);
            db = MyConnection::getDb();
        }
        QSqlQuery q(db);
        if(!q.exec(sql))
        {
            QSqlError tempErr = q.lastError();
            Mymethod::record(tempErr.text()+" sql:"+sql,PRINT_ERR);
        }
        else
        {
            Mymethod::record("insert "+db.databaseName()+" ok.",PRINT_OK);
        }
        MyConnection::removeDb(db);

 

 

 

 

2019.10.24:

今天出現了個問題,剛好是程序員節,md調試了了一天。

問題描述:

線程A不斷產生sql語句,需要讓兩個數據庫分別執行這個sql語句。所以在線程A中建立兩個子線程B和C,分別對應兩個數據庫。然后發現兩個線程同時啟動【即兩個線程同時調Qt訪問mysql的dll】會報錯:

 

 解決:

在其中一個子線程中初次調用的時候延時1s:

    static bool test=true;
    if(test)
    {
        QThread::sleep(1);
        test=false;
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM