数据库连接池的意义
数据库连接池是用来干嘛的呢?无非就是减少时间,性能损耗的
首次创建的连接可以进行缓存, 如果有空闲则提取出来直接使用,不需要重新创建与打开连接的操作(节省了很多时间)
但是我们要明白,那我们准备好一个连接就行了,为什么叫连接池呢?
数据库连接池是提供给多线程使用的,你如果程序只有一个主线程,那你只能同时使用一个连接。
但是假设如果是多线程,那就可能同时使用多个连接,这种时候就需要引入连接池的概念
需要的线程从池子里面取出来一个,用完放回去。
是可以跨越线程使用,是可以打乱使用的
然而,qt中数据库连接qsqldatabase无法给不是创建他的线程进行使用,是线程不安全的。
那qt就没办法实现连接池了吗?并不是
连接池本身的概念就是希望,不要重复创建new与开启open导致浪费大量的时间,而实际就是一个缓存连接的概念。
那我们可以,不同的线程的连接缓存池子中,当该线程释放,也将其连接从池子中释放出去,
但是无法打乱使用,需要一一对应使用。
所以我们这里如果做到使用自己线程的资源我们需要引入QThreadStorage这个
当然也存在缺陷:
如果有10几个线程不就得有10几个连接吗,是的,
甚至有的线程只用一次,迟迟不释放,又不给其他线程使用,这个就是他的缺点
而线程又分为,短期与长期线程
长期线程就是很难关闭,一般伴随程序的启动到程序的结束
短期线程就是一般是个消费者线程或者任务线程等,用完就释放
而如何管理多线程,我随思着也没人敢乱搞,到处播种,就是到处乱开
一般都是集中处理,集中发放
所以尽量控制线程个数这样子就可以约束连接池中连接数量
而怎么控制呢?qt中开启多线程方式有几种
一种就是派生qthread,这种就是属于到处乱开
一种就是派生qobject,这种比较好约束,使用movetothread将其转移到指定的线程中运行
这样子就是使用qthread与qobject进行集中管理处理
还有一种就是任务线程池QThreadPool ;执行任务std::bind或者std::funtion 或者lambda写法还有QRunnable
请参考https://blog.youkuaiyun.com/LeoLei8060/article/details/139633675
代码
//获取连接这么处理就稳妥
QSqlDatabase PooledDataSource::getConnection()
{
qDebug()<< QThread::currentThreadId();
QSqlDatabase conn = m_localConnections.localData();
if(!conn.isValid()){
QString connectionName = m_datasourceName + "_"+
QStringLiteral("%1").arg(quintptr(QThread::currentThreadId()));
conn = QSqlDatabase::addDatabase(m_driverName,connectionName);
conn.setDatabaseName(m_databaseName);
conn.setUserName(m_username);
conn.setPassword(m_password);
conn.open();
m_localConnections.setLocalData(conn);
connect(QThread::currentThread(),&QThread::finished,this,[=]{
QSqlDatabase::removeDatabase(connectionName);
});
}
return conn;
}
使用
QThreadPool* pool = QThreadPool::globalInstance();
pool->setMaxThreadCount(4);
QPushButton *btn = new QPushButton(this);
connect(btn,&QPushButton::clicked,this,[=]{
MySqlWork *sql1 = new MySqlWork;
pool->start(sql1);
});