永利皇宫463现在官网成立于2015年底,是一家专注于高精度3D机器视觉模组研发、生产及销售的高科技企业。
公司自主研发的3D机器视觉模组采用激光/DLP白光编码光栅结构光+双工业相机方案,还原物体三维信息,广泛应用于消费电子领域、工业领域和安防领域,具有精度高、速度快、成本低的优势。
基于C++语言实现Qt框架下的数据库连接池应用
随着互联网和大数据时代的到来,数据库操作已经成为许多企业和应用程序不可或缺的重要部分。数据库连接池技术的应用,可以提高数据库使用效率,减少资源和时间的浪费。基于C++语言的Qt框架,也可以实现数据库连接池技术,本文将介绍如何使用Qt实现数据库连接池,让你的数据库操作更加高效。
一、什么是数据库连接池
数据库连接池是一种通过预先建立多个数据库连接,在应用程序的运行过程中重复利用数据库连接的技术。通俗的说,就是在应用程序中预先建立多个数据库连接,当需要访问数据库时从连接池中获取一个数据库连接,用完后还回连接池中。这种利用池化技术的方式能够降低新建连接的时间和资源消耗,提高数据库的操作效率。下面,我们将使用Qt实现数据库连接池。
二、Qt中数据库连接的建立与使用
在Qt中,数据库连接的建立与使用非常简单。首先需要创建一个QSqlDatabase实例,在该实例中设置需要连接的数据库类型、主机和用户名等信息。然后,使用QSqlDatabase::open()函数打开该数据库连接,并进行一些操作。
#include
#include
#include
QSqlDatabase db = QSqlDatabase::addDatabase(“QMYSQL”);
db.setHostName(“localhost”);
db.setDatabaseName(“test”);
db.setUserName(“root”);
db.setPassword(“password”);
if(db.open())
{
qDebug() << “Open database success !”;
QSqlQuery query(db);
query.exec(“select * from testDB”);
while(query.next())
qDebug() << query.value(0).toString();
}
上述代码演示了在Qt中连接MySQL数据库的过程。首先使用QSqlDatabase::addDatabase(“QMYSQL”)函数创建一个QSqlDatabase实例,在该实例中设置需要连接的数据库类型、主机和用户名等信息。然后,使用QSqlDatabase::open()函数打开该数据库连接。在数据库连接成功后,使用QSqlQuery实例进行一些操作。注意,一定要在使用完QSqlQuery对象后,调用其~QSqlQuery()函数释放资源。
三、Qt实现数据库连接池
下面,我们将基于Qt实现一个简单的数据库连接池。创建一个ConnectionPool类,该类中包含了多个数据库连接对象。ConnectionPool的.h文件内容如下:
#ifndef CONNECTIONPOOL_H
#define CONNECTIONPOOL_H
#include
#include
#include
#include
#include
#include
#include
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
QQueue
// 数据库信息
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 ConnectionPool *instance;
};
#endif // CONNECTIONPOOL
SqlDatabase是Qt框架中操作数据库的重要类之一,可以通过该类实现数据库连接的建立和操作。ConnectionPool类是自定义的一个库连接池类,在该类中定义了数据库连接的各种属性,并包含了多个数据库连接对象。
在ConnectionPool类的实现文件中,我们将实现具体的方法。定义如下静态变量:
QMutex ConnectionPool::mutex;
QWaitCondition ConnectionPool::waitConnection;
ConnectionPool* ConnectionPool::instance = nullptr;
用静态变量ConnectionPool::instance来存储ConnectionPool类的唯一实例,同时使用QMutex和QWaitCondition分别保护多线程的同步和条件变量的使用。
接着,实现单态模式中的getInstance()方法。该方法用于返回ConnectionPool类的唯一实例:
ConnectionPool& ConnectionPool::getInstance() {
if (nullptr == instance) {
QMutexLocker locker(&mutex);
if (nullptr == instance) {
instance = new ConnectionPool();
}
}
return *instance;
}
在getInstance ()方法中,使用互斥锁QMutexLocker保证了多线程同步,使用双重检查锁定机制确保了ConnectionPool类的唯一实例。
然后,我们可以实现如下连接的建立与关闭方法openConnection()和closeConnection()。openConnection()方法用于从连接池中获取一个数据库连接,closeConnection()方法用于还回这个数据库连接:
QSqlDatabase ConnectionPool::openConnection() {
ConnectionPool& pool = ConnectionPool::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 ConnectionPool::closeConnection(QSqlDatabase connection) {
ConnectionPool& pool = ConnectionPool::getInstance();
QString connectionName = connection.connectionName();
// 如果是我们创建的连接,从 used 里删除,放入 unused 里
if (pool.usedConnectionNames.contains(connectionName)) {
QMutexLocker locker(&mutex);
pool.usedConnectionNames.removeOne(connectionName);
pool.unusedConnectionNames.enqueue(connectionName);
waitConnection.wakeOne();
}
}
在openConnection()方法中,首先获取互斥锁QMutexLock,在连接池中查找是否有空闲连接。如果有,直接返回该连接,否则查看可用的连接数是否达到上限,如果没有,则创建新的连接。当新连接创建成功后,检查该连接是否打开,如果打开,则更新连接数。最后释放互斥锁。
closeConnection()方法用于还回连接到连接池中,并检查连接池中连接数量是否超过设定的更大值,如果超过,则移除最早的连接。程序执行完该方法后,也应该释放互斥锁。
我们实现ConnectionPool的构造函数和析构函数:
ConnectionPool::ConnectionPool() {
hostName = "127.0.0.1";//主机名
databaseName = "DRIVER={SQL SERVER};SERVER=127.0.0.1;DATABASE=testDB";//需要访问的数据库
username = "sa"; //用户名
password = "123456"; //密码
databaseType = "QODBC"; //数据库类型
testOnBorrow = true;
testOnBorrowSql = "SELECT 1";
maxWaitTime = 1000;
waitInterval = 200;
maxConnectionCount = 1000;
}
ConnectionPool::~ConnectionPool() {
// 销毁连接池的时候删除所有的连接
foreach(QString connectionName, usedConnectionNames) {
QSqlDatabase::removeDatabase(connectionName);
}
foreach(QString connectionName, unusedConnectionNames) {
QSqlDatabase::removeDatabase(connectionName);
}
}
void ConnectionPool::release() {
QMutexLocker locker(&mutex);
delete instance;
instance = nullptr;
}
QSqlDatabase ConnectionPool::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 datatabase error:" << db1.lastError().text();
return QSqlDatabase();
}
}
return db1;
}
// 创建一个新的连接 注意:如果需要跨线程操作时这里需要连接时需要设置个静态连接数据库
QSqlDatabase db = QSqlDatabase::addDatabase(databaseType, connectionName);
db.setHostName(hostName);
db.setDatabaseName(databaseName);
db.setUserName(username);
db.setPassword(password);
db.setPort(3306);
if (!db.open()) {
qDebug() << "Open datatabase error:" << db.lastError().text();
return QSqlDatabase();
}
return db;
}
在ConnectionPool类的构造函数中,预先创建maxConnectionCount个数据库连接,并存储在usedConnectionNames中。在该构造函数调用后,用户可以直接通过openConnection()方法获取连接,加快数据库操作的速度。
数据库连接长时间不操作是可能会断开,检查数据库的配置连接时间,一般会有时间限制,建议你程序启动需要和数据库交互时,先判断数据库是否是连接状态,未连接时重新连接。
关于qt中数据库连接池的介绍到此就结束了。
如有侵权,联系删除。