1、connectionpool.h
#ifndef CONNECTIONPOOL_H
#define CONNECTIONPOOL_H
#include "singleton.h"
#include <QSqlDatabase>
#include <QString>
#include <QStack>
#include <QSemaphore>
class ConnectionPoolObject;
class ConnectionPool
{
SINGLETON(ConnectionPool)
public:
void destory(); // 销毁连接池,关闭所有的数据库连接
QSqlDatabase openConnection(); // 获取数据库连接
void closeConnection(const QSqlDatabase& connection); // 释放数据库连接回连接池
private:
QSqlDatabase createConnection(const QString& connectionName); // 创建数据库连接
ConnectionPoolObject * object;
};
class ConnectionPoolObject
{
public:
ConnectionPoolObject();
~ConnectionPoolObject();
QStack<QString> usedConnectionNames; // 已使用的数据库连接名
QStack<QString> unusedConnectionNames; // 未使用的数据库连接名
// 数据库信息
QString databaseName;
QString databaseType;
bool testOnBorrow; // 取得连接的时候验证连接有效
QString testOnBorrowSql; // 测试访问数据库的 SQL
int maxWaitTime; // 获取连接最大等待时间
int maxConnectionCount; // 最大连接数
QSemaphore *semaphore;
static QMutex mutex;
static int lastKey; // 用来创建连接的名字,保证连接名字不会重复
};
#endif
2、connectionpool.cpp
#include "connectionpool.h"
#include <QtSql>
#include <QCoreApplication>
QMutex ConnectionPoolObject::mutex;
int ConnectionPoolObject::lastKey = 0;
ConnectionPoolObject::ConnectionPoolObject()
{
QString dbPath;
dbPath = QCoreApplication::applicationDirPath() +"/db/NELD_TSV790.db";
databaseName = dbPath;
databaseType = "QSQLITE";
testOnBorrow = true;
testOnBorrowSql = "SELECT 1";
maxWaitTime = 5000;
maxConnectionCount = 15;
semaphore = new QSemaphore(maxConnectionCount);
}
ConnectionPoolObject::~ConnectionPoolObject()
{
// 销毁连接池的时候删除所有的连接
foreach (QString connectionName, usedConnectionNames)
{
QSqlDatabase::removeDatabase(connectionName);
}
foreach (QString connectionName, unusedConnectionNames)
{
QSqlDatabase::removeDatabase(connectionName);
}
delete semaphore;
}
ConnectionPool::ConnectionPool() : object(new ConnectionPoolObject)
{
}
ConnectionPool::~ConnectionPool()
{
delete object;
}
QSqlDatabase ConnectionPool::openConnection()
{
Q_ASSERT(object != NULL);
if (object->semaphore->tryAcquire(1, object->maxWaitTime))
{
ConnectionPoolObject::mutex.lock();
QString connectionName;
if (object->unusedConnectionNames.size() > 0)
{
connectionName = object->unusedConnectionNames.pop();
}
else
{
connectionName = QString("C%1").arg(++ConnectionPoolObject::lastKey);
}
object->usedConnectionNames.push(connectionName);
ConnectionPoolObject::mutex.unlock();
QSqlDatabase db = createConnection(connectionName);
if (!db.isOpen())
{
ConnectionPoolObject::mutex.lock();
// object->usedConnectionNames.removeOne(connectionName);
QStack<QString> tempStack;
while (!object->usedConnectionNames.isEmpty())
{
QString top = object->usedConnectionNames.pop();
if (top != connectionName)
{
tempStack.push(top);
}
}
// 重新构建原始 QStack,不包含指定名称的元素
while (!tempStack.isEmpty())
{
object->usedConnectionNames.push(tempStack.pop());
}
ConnectionPoolObject::mutex.unlock();
object->semaphore->release();
}
return db;
}
else
{
return QSqlDatabase(); // 创建连接超时,返回一个无效连接
}
}
void ConnectionPool::closeConnection(const QSqlDatabase& connection)
{
Q_ASSERT(object != NULL);
QString connectionName = connection.connectionName();
if (object->usedConnectionNames.contains(connectionName))
{
QMutexLocker locker(&ConnectionPoolObject::mutex);
// object->usedConnectionNames.removeOne(connectionName);
QStack<QString> tempStack;
while (!object->usedConnectionNames.isEmpty()) {
QString top = object->usedConnectionNames.pop();
if (top != connectionName) {
tempStack.push(top);
}
}
// 重新构建原始 QStack,不包含指定名称的元素
while (!tempStack.isEmpty()) {
object->usedConnectionNames.push(tempStack.pop());
}
object->unusedConnectionNames.push(connectionName);
object->semaphore->release();
}
}
QSqlDatabase ConnectionPool::createConnection(const QString& connectionName)
{
Q_ASSERT(object != NULL);
if (QSqlDatabase::contains(connectionName))
{
QSqlDatabase existDb = QSqlDatabase::database(connectionName);
if (object->testOnBorrow)
{
QSqlQuery query(object->testOnBorrowSql, existDb);
if (query.lastError().type() != QSqlError::NoError && !existDb.open())
{
return QSqlDatabase();
}
}
return existDb;
}
QSqlDatabase db = QSqlDatabase::addDatabase(object->databaseType, connectionName);
db.setDatabaseName(object->databaseName);
if (!db.open())
{
return QSqlDatabase();
}
return db;
}
void ConnectionPool::destory()
{
if (object != NULL)
{
ConnectionPoolObject::mutex.lock();
delete object;
object = NULL;
ConnectionPoolObject::mutex.unlock();
}
}
3、Singleton.h
#ifndef SINGLETON_H
#define SINGLETON_H
#include <QMutex>
#include <QScopedPointer>
template <typename T>
class Singleton{
public:
Singleton(const Singleton& other);
Singleton<T>& operator=(const Singleton& other);
static T& getInstance();
private:
static QMutex mutex;
static QScopedPointer<T> instance;
};
template<typename T> QMutex Singleton<T>::mutex;
template<typename T> QScopedPointer<T> Singleton<T>::instance;
template<typename T>
T& Singleton<T>::getInstance()
{
if (instance.isNull())
{
mutex.lock();
if (instance.isNull())
{
instance.reset(new T());
}
mutex.unlock();
}
return *instance.data();
}
#define SINGLETON(Class) \
private: \
Class(); \
~Class(); \
Class(const Class& other); \
Class& operator=(const Class& other); \
friend class Singleton<Class>; \
friend struct QScopedPointerDeleter<Class>;
#endif
4、示例
SqliteDB g_db;
1、QSqlDatabase m_dataBase;
2、打开数据库
bool bRet = m_dataBase.isOpen()
m_dataBase = Singleton<ConnectionPool>::getInstance().openConnection();
3、检查是否存在表:
bool bRet = m_dataBase.tables().contains(m_TableName) ;
4、创建数据库表
QSqlQuery createTableQuery(m_dataBase);
createTableQuery.exec(m_TableName);
5、插入记录
QSqlQuery insertQuery(m_dataBase);
insertQuery.exec(insertSql)
6、更新记录
QSqlQuery updateQuery(m_dataBase);
updateQuery.exec(updateSql)
7、查询记录
QSqlQuery query(m_dataBase);
query.prepare(sql);
query.exec();
if (query.next())
{
experInfo.No = query.value("no").toString();
experInfo.Person = query.value("person").toString();
... ...
}
8、 关闭连接
Singleton<ConnectionPool>::getInstance().closeConnection(m_dataBase);
简单说明:
QStack 是 Qt 容器类库中提供的栈(LIFO,后进先出) 数据结构,继承自 QVector,因此它的底层实现是动态数组,兼具栈的操作特性和向量的高效访问能力。
核心特性
- 后进先出(LIFO):只能从栈顶插入 / 删除元素,不支持随机位置的插入操作。
- 继承自
QVector:可以直接使用QVector的方法(如size()、isEmpty()、at()等),同时扩展了栈专用接口。 - 值语义:元素会被拷贝存储,支持基本数据类型、Qt 数据类型及自定义类型(需实现拷贝构造函数)。
代码示例
cpp
运行
#include <QStack>
#include <QDebug>
int main() {
QStack<int> stack;
// 压入元素
stack.push(10);
stack.push(20);
stack.push(30);
// 访问栈顶元素
qDebug() << "Top element:" << stack.top(); // 输出 30
// 弹出栈顶元素
stack.pop();
qDebug() << "Top after pop:" << stack.top(); // 输出 20
// 遍历栈(注意:遍历顺序不是栈的弹出顺序)
for (int val : stack) {
qDebug() << val; // 输出 10, 20
}
return 0;
}