zoukankan      html  css  js  c++  java
  • 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() << " " << 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:QtQt5.3.15.3msvc2012路径下的文件夹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;
        }
  • 相关阅读:
    springboot项目下载文件功能中-切面-导致的下载文件失败的bug
    解决laydate动态设置初始值的问题
    简易MySQL存储过程
    css选择器(第n个类选择器)的坑
    session过期情况下ajax请求不会触发重新登录的问题
    session过期情况下ajax请求不会触发重新登录的问题
    springboot配置多数据源mongodb
    css平移动画的实现
    springboot中使用JOIN实现关联表查询
    解决springboot项目中@Value注解参数值为null的问题
  • 原文地址:https://www.cnblogs.com/judes/p/7305953.html
Copyright © 2011-2022 走看看