一、singleton模式介绍
singleton模式能够为一个类定义唯一的对象,并通过一个静态成员函数访问这个对象。一个更简单的做法是在一个函数中将该类的对象定义为一个静态局部对象,然后让该函数返回该对象地址。
二、使用QAtomicPointer实现多线程操作数据库
本人直接贴代码,不想讲原理了。你们直接看吧,同时也把测试代码贴出来
头文件:connectionpool.h
#ifndef CONNECTIONPOOL_H
#define CONNECTIONPOOL_H
#include <QtSql>
#include <QQueue>
#include <QString>
#include <QMutex>
#include <QMutexLocker>
#include<QAtomicPointer>
class ConnectionPool {
public:
static void release(); // 关闭所有的数据库连接
static QSqlDatabase openConnection(); // 获取数据库连接
static void closeConnection(QSqlDatabase connection); // 释放数据库连接回连接池
~ConnectionPool();
static ConnectionPool& getInstance();//单例初始化
public:
QSqlDatabase createConnection(const QString &connectionName); // 创建数据库连接
QQueue<QString> usedConnectionNames; // 已使用的数据库连接名
QQueue<QString> unusedConnectionNames; // 未使用的数据库连接名
// 数据库信息
QString hostName;
QString databaseName;
QString username;
QString password;
QString databaseType;
int port;
bool testOnBorrow; // 取得连接的时候验证连接是否有效
QString testOnBorrowSql; // 测试访问数据库的 SQL
int maxWaitTime; // 获取连接最大等待时间
int waitInterval; // 尝试获取连接时等待间隔时间
int maxConnectionCount; // 最大连接数
private:
ConnectionPool();
ConnectionPool(const ConnectionPool &other);
ConnectionPool& operator=(const ConnectionPool &other);
static QMutex mutex;
static QWaitCondition waitConnection;
static QAtomicPointer<ConnectionPool> m_instance;
};
#endif // CONNECTIONPOOL_H
源文件:connectionpool.cpp
#include "connectionpool.h"
#include <QDebug>
QMutex ConnectionPool::mutex;
QAtomicPointer<ConnectionPool> ConnectionPool::m_instance=nullptr;
QWaitCondition ConnectionPool::waitConnection;
ConnectionPool::ConnectionPool() {
// 创建数据库连接的这些信息在实际开发的时都需要通过读取配置文件得到,
// 这里为了演示方便所以写死在了代码里。
// QString str=QDir::currentPath()+"/Profile/config.ini";
//QSettings setting(str, QSettings::IniFormat);//读配置文件 不写清除路径,一般就是相对路径处
// setting.beginGroup("DataBaseServer");
//QString IP = setting.value("IP").toString();
// QString DataBase = setting.value("DataBase").toString();
//QString UserName = setting.value("UserName").toString();
//QString PassWord = setting.value("PassWord").toString();
// int Port=setting.value("Port").toInt();
// hostName = IP;
//port=Port;
databaseName = "tset.db";
//username = UserName;
// password = PassWord;
databaseType = "QSQLITE";
testOnBorrow = true;
testOnBorrowSql = "SELECT 1";
maxWaitTime = 1000;
waitInterval = 200;
maxConnectionCount = 5;
}
ConnectionPool::~ConnectionPool() {
// 销毁连接池的时候删除所有的连接
foreach(QString connectionName, usedConnectionNames) {
QSqlDatabase::removeDatabase(connectionName);
}
foreach(QString connectionName, unusedConnectionNames) {
QSqlDatabase::removeDatabase(connectionName);
}
}
ConnectionPool& ConnectionPool::getInstance()
{
// if (nullptr == instance)
// {
// QMutexLocker locker(&mutex);
// if (nullptr == instance)
// {
// instance = new ConnectionPool();
// }
// }
// return *instance;
#ifndef Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE
if(!QAtomicPointer<ConnectionPool>::isTestAndSetNative())
qDebug()<<"Error: TestAndSetNative not supported!";
#endif
{
QMutexLocker locker(&mutex);
if(m_instance.testAndSetOrdered(nullptr,nullptr))
{
m_instance.testAndSetOrdered(nullptr,new ConnectionPool);
}
return *m_instance.load();
}
}
void ConnectionPool::release() {
QMutexLocker locker(&mutex);
delete m_instance;
m_instance = nullptr;
}
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();
}
}
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(port);
if (!db.open()) {
qDebug() << "Open datatabase error:" << db.lastError().text();
return QSqlDatabase();
}
return db;
}
测试介绍:采用Qtconcurrent模块中的map()函数。map函数有两个参数,Sequence &sequence,和MapFunctor function。sequence为QList类型,function为函数,其参数为sequence得成员。map函数回会自动开辟出对应于sequence的数量的临时线程。
sequence:
QStringList list;
list.append("ui");
list.append("fhjd");
list.append("vkdll");
function:
void getsqlData(QString name)
{
time_t begin,end;
begin=clock();
QSqlDatabase db= ConnectionPool::openConnection();
QSqlQuery sql_query(db);
sql_query.exec("select * from student");
if(!sql_query.exec())
{
qDebug()<<sql_query.lastError();
}
else
{
while(sql_query.next())
{
int id = sql_query.value(0).toInt();
QString name = sql_query.value(1).toString();
int age = sql_query.value(2).toInt();
qDebug()<<QString("id:%1 name:%2 age:%3").arg(id).arg(name).arg(age);
}
}
qDebug()<<name<<QThread::currentThread();
ConnectionPool::closeConnection(db);
end=clock();
cout<< "Running time is: "<<static_cast<double>(end-begin)/CLOCKS_PER_SEC*1000<<"ms"<<endl;
}
完整测试代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include"connectionpool.h"
#include
using namespace std;
void getsqlData(QString name)
{
time_t begin,end;
begin=clock();
QSqlDatabase db= ConnectionPool::openConnection();
QSqlQuery sql_query(db);
sql_query.exec(“select * from student”);
if(!sql_query.exec())
{
qDebug()<<sql_query.lastError();
}
else
{
while(sql_query.next())
{
int id = sql_query.value(0).toInt();
QString name = sql_query.value(1).toString();
int age = sql_query.value(2).toInt();
qDebug()<<QString(“id:%1 name:%2 age:%3”).arg(id).arg(name).arg(age);
}
}
qDebug()<<name<<QThread::currentThread();
ConnectionPool::closeConnection(db);
end=clock();
cout<< "Running time is: "<<static_cast(end-begin)/CLOCKS_PER_SEC*1000<<“ms”<<endl;
}int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QStringList list;
list.append(“ui”);
list.append(“fhjd”);
list.append(“vkdll”);
QFuture f=QtConcurrent::map(list,getsqlData);
return a.exec();
}
测试结果:
不解释结果了,写的很糙。