我试图在某种程度上建立一个MySQL连接池。用例是这样的:
当我从它请求连接时(QSqlDatabase对象),它将基于当前线程id生成一个连接名称作为字符串。如果我已经拥有该名称的开放连接,它将返回该名称。否则,它将打开与该名称的连接,它将返回它。
我还保留一个标志,指示连接是否已被使用以及上次使用的时间戳。我还有一个QTimer,它会定期打勾并关闭未使用但未在指定时间内使用的连接。
我认为实施很好。但是,每隔一段时间我的getConnection()就会卡住。这是来自gdb的堆栈跟踪。当发生这种情况时,程序不会崩溃或类似的事情,但getConnection()不会返回。
#0 pthread_once () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S:94
#1 0x00007f1fae288199 in get_charset_by_csname () from /usr/lib/x86_64-linux-gnu/libmysqlclient.so.18
#2 0x00007f1fae271a97 in mysql_init_character_set () from /usr/lib/x86_64-linux-gnu/libmysqlclient.so.18
#3 0x00007f1fae272960 in mysql_real_connect () from /usr/lib/x86_64-linux-gnu/libmysqlclient.so.18
#4 0x00007f1fae77c0ad in ?? () from /usr/local/Qt-5.2.0/plugins/sqldrivers/libqsqlmysql.so
#5 0x00007f1fb5bd0251 in QSqlDatabase::open() () from /usr/local/Qt-5.2.0/lib/libQt5Sql.so.5
#6 0x00007f1fb895b479 in ConnectionPool::getConnection(QString const&) () from /home/user/demo1/lib/libMySqlConn.so
以下是我的代码片段:
// Members of ConnectionPool:
// QMutex mMutex
// QHash<QString, ConnectionData> mConnections;
struct ConnectionData
{
QSqlDatabase* pDatabase;
QDateTime lastUsed;
int refCount = 0;
};
QString ConnectionPool::getConnectionName()
{
const quint64 tid = *reinterpret_cast<const quint64 *>(QThread::currentThreadId());
return QString("%1").arg(tid, 12, 16, '0');
}
QSqlDatabase* ConnectionPool::getConnection(const QString& connName)
{
QSqlDatabase* pDatabase = new QSqlDatabase(QSqlDatabase::addDatabase("QMYSQL", connName));
pDatabase->setHostName("localhost");
pDatabase->setPort(3306);
pDatabase->setDatabaseName("test1");
pDatabase->setUserName("user");
pDatabase->setPassword("pass");
pDatabase->setConnectOptions("MYSQL_OPT_RECONNECT=1");
if (!pDatabase->open())
{
delete pDatabase;
pDatabase = nullptr;
QSqlDatabase::removeDatabase(connName);
}
return pDatabase;
}
bool ConnectionPool::connection(QSqlDatabase& db)
{
const QString connName = getConnectionName();
QMutexLocker locker(&mMutex);
if (mConnections.contains(connName))
{
ConnectionData& conndata = mConnections[connName];
if (conndata.pDatabase->isOpen())
{
db = *conndata.pDatabase;
conndata.refCount++;
conndata.lastUsed = QDateTime::currentDateTime();
return true;
}
delete conndata.pDatabase;
mConnections.remove(connName);
QSqlDatabase::removeDatabase(connName);
}
QSqlDatabase* pDatabase = getConnection(connName);
if (!pDatabase)
return false;
ConnectionData conndata;
conndata.refCount = 1;
conndata.pDatabase = pDatabase;
conndata.lastUsed = QDateTime::currentDateTime();
mConnections.insert(connName, conndata);
db = *pDatabase;
return true;
}