.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 #include "connectionpool.h" #include <QDebug> #include <QSettings> QMutex ConnectionPool::mutex; QWaitCondition ConnectionPool::waitConnection; ConnectionPool* ConnectionPool::instance = NULL ; ConnectionPool::ConnectionPool () { QString apppath=QCoreApplication::applicationDirPath (); QString mysqlconfig=apppath+"/CFG/mysqlconfig.ini" ; QSettings* m_IniFile = new QSettings (mysqlconfig, QSettings::IniFormat); m_IniFile ->beginGroup ("mysqlserver" ); hostName= m_IniFile->value ("ip" ).toString (); port=m_IniFile->value ("port" ).toInt (); databaseName=m_IniFile->value ("database" ).toString (); username=m_IniFile->value ("username" ).toString (); password=m_IniFile->value ("password" ).toString (); m_IniFile->endGroup (); m_IniFile->deleteLater (); databaseType = "QMYSQL" ; testOnBorrow = true ; testOnBorrowSql = "SELECT 1" ; waitInterval = 1000 ; maxConnectionCount = 10 ; maxWaitTime = waitInterval*maxConnectionCount; } ConnectionPool::~ConnectionPool () { foreach(QString connectionName, usedConnectionNames) { QSqlDatabase::removeDatabase (connectionName); } foreach(QString connectionName, unusedConnectionNames) { QSqlDatabase::removeDatabase (connectionName); } }ConnectionPool& ConnectionPool::getInstance () { if (NULL == instance) { QMutexLocker locker (&mutex) ; if (NULL == instance) { instance = new ConnectionPool (); } } return *instance; }void ConnectionPool::release () { QMutexLocker locker (&mutex) ; delete instance; instance = NULL ; }QSqlDatabase ConnectionPool::openConnection () { ConnectionPool& pool = ConnectionPool::getInstance (); QString connectionName; QMutexLocker locker (&mutex) ; int connectionCount = pool.unusedConnectionNames.size () + pool.usedConnectionNames.size (); while (pool.unusedConnectionNames.size () == 0 && connectionCount == pool.maxConnectionCount){ 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); if (db.isOpen ()) { pool.usedConnectionNames.enqueue (connectionName); } return db; }void ConnectionPool::closeConnection (QSqlDatabase connection) { ConnectionPool& pool = ConnectionPool::getInstance (); QString connectionName = connection.connectionName (); if (pool.usedConnectionNames.contains (connectionName)) { QMutexLocker locker (&mutex) ; pool.usedConnectionNames.removeOne (connectionName); pool.unusedConnectionNames.enqueue (connectionName); waitConnection.wakeOne (); } }QSqlDatabase ConnectionPool::createConnection (const QString &connectionName) { if (QSqlDatabase::contains (connectionName)) { QSqlDatabase db1 = QSqlDatabase::database (connectionName); if (testOnBorrow) { 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.setPort (port); db.setDatabaseName (databaseName); db.setUserName (username); db.setPassword (password); if (!db.open ()) { qDebug () << "Open datatabase error:" << db.lastError ().text (); return QSqlDatabase (); } return db; }
.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #ifndef CONNECTIONPOOL_H #define CONNECTIONPOOL_H #include <QtSql> #include <QQueue> #include <QString> #include <QMutex> #include <QMutexLocker> 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; int port; QString databaseName; QString username; QString password; QString databaseType; bool testOnBorrow; QString testOnBorrowSql; int maxWaitTime; int waitInterval; int maxConnectionCount; static QMutex mutex; static QWaitCondition waitConnection; static ConnectionPool *instance; };#endif
QSqldatabase::addDatabase(“connectionname”)创建的数据库连接对象,只能在同一个线程中使用,但是一旦按照某个连接名创建了连接,那么按照QSqldatabase::database(“connectionname”)获取的连接实例可以跨线程使用,但是注意跨线程时不同线程同时使用一个连接名创建的连接,则会引起资源竞争,导致意外的错误,具体的错误为:2006:server has gone away 或者2013 lost connection,需要mutex锁保护一下,或者使用数据库连接池的概念,保证每次使用的连接没有和其他线程产生竞争。