QT database连接问题

在一个QT-Mysql的项目中,偶尔出现连接数据库很慢和连接失败的现象,查看后台能看到这样的警告

Error in my_thread_global_end(): 1 threads didn't exit

后来在qt论坛上看到类似的问题,提问者给出了以下代码,用100个线程同时连接数据再断开,果然能重现问题。

class Client: public QRunnable
{
public:
    virtual void run();
};
void Client::run()
{
    QString sID = QString::number((unsigned long long)QThread::currentThreadId());
    QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", sID); // unique connection name

    db.setHostName("localhost");
    db.setDatabaseName("test");
    db.setUserName("me");
    db.setPassword("mypass");

    db.open();
    // do something query...
    db.close(); // 对象并未释放,无法remove
    QSqlDatabase::removeDatabase(sID);
}
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QThreadPool pool;
    pool.setMaxThreadCount(100);

    for (int i = 0; i < 100; ++i)
    {
        Client *client = new Client;
        bool started = pool.tryStart(client);
        Q_ASSERT(started);
    }
    pool.waitForDone();
    return 0;
}

不过先出了另一个问题:removeDatabase: connection '**' is still in use, all queries will cease to work

查了一下,原因是QSqlDatabase对象close()时连接并未完全释放,也就无法remove. 改成指针的形式可以解决  

    QSqlDatabase *pdb = new QSqlDatabase();
    *pdb = QSqlDatabase::addDatabase("QMYSQL", sID); // unique connection name
    pdb->set...;
    pdb->open();
    pdb->close();
    delete pdb; // 释放对象
    pdb = NULL;
    QSqlDatabase::removeDatabase(sID);

解决这个之后,连接数据库很慢和失败、警告都出现了。经过反复尝试,发现QSqlDatabase::addDatabase/open不是线程安全的, 不能被打断,加锁保护后完全正常了。

QMutex gMutexdb; // global mutex for db-open
    gMutexdb.Lock();
    *pdb = QSqlDatabase::addDatabase("QMYSQL", sID); // unique connection name
    pdb->set...;
    pdb->open();
    gMutexdb.Unlock();

不过这种多数据库连接,应该做一个连接池来管理。

posted @ 2017-04-07 10:43  chaos77  阅读(5243)  评论(0编辑  收藏  举报