QSqlDatabase的进一步封装(多线程支持+更加简单的操作)——同时支持MySQL, SQL Server和Sqlite
开发背景:
1.直接用QSqlDatabase我觉得太麻烦了;
2.对于某些数据库,多个线程同时使用一个QSqlDatabase的时候会崩溃;
3.这段时间没什么干货放出来觉得浑身不舒服,就想写一个。
于是,我就封装了一下
只要简单的实例化,然后通过query()就可以拿到QSqlQuery的实例化对象。
还自带计时,一段时间不用可自动关闭,既保证效率也不占用无用资源。
注:需要C++11的支持
不多说,上代码:
JasonQt_Database.h
- #ifndef __JasonQt_Database_h__
- #define __JasonQt_Database_h__
- // C++ lib import
- #include <functional>
- // Qt lib import
- #include <QtCore>
- #include <QtSql>
- #define PropertyDeclare(Type, Name, setName, ...) \
- private: \
- Type m_ ## Name __VA_ARGS__; \
- public: \
- inline const Type &Name(void) const { return m_ ## Name; } \
- inline void setName(const Type &Name) { m_ ## Name = Name; } \
- private:
- namespace JasonQt_Database
- {
- enum DatabaseModeEnum{ DatabaseNameMode, DatabaseHostMode };
- enum QueryMode { QueryAutoMode, QueryMultiMode, QuerySingleMode };
- class DatabaseSettings
- {
- private:
- PropertyDeclare(DatabaseModeEnum, databaseMode, setDatabaseMode)
- PropertyDeclare(QString, databaseType, setDatabaseType)
- PropertyDeclare(QString, connectionName, setConnectionName)
- // File mode
- PropertyDeclare(QString, nameModeName, setNameModeName)
- // Host mode
- PropertyDeclare(QString, hostModeHostName, setHostModeHostName)
- PropertyDeclare(QString, hostModeDatabaseName, setHostModeDatabaseName)
- PropertyDeclare(QString, hostModeUserName, setHostModeUserName)
- PropertyDeclare(QString, hostModePassword, setHostModePassword)
- private:
- DatabaseSettings(const DatabaseModeEnum &databastMode, const QString &databaseType, const QString &connectionName);
- public:
- DatabaseSettings(const QString &databaseType, const QString &connectionName, const QString &nameModeName);
- DatabaseSettings(const QString &databaseType, const QString &connectionName, const QString &hostModeHostName, const QString &hostModeDatabaseName, const QString &hostModeUserName, const QString &hostModePassword);
- };
- class ConnectSettings
- {
- private:
- PropertyDeclare(int, maxOpenTime, setMaxOpenTime)
- PropertyDeclare(QueryMode, queryMode, setQueryMode)
- PropertyDeclare(int, minWaitTime, setMinWaitTime)
- public:
- ConnectSettings(const int &maxOpenTime = 60 * 1000, const QueryMode &queryMode = QueryAutoMode, const int &minWaitTime = -1);
- };
- class Query
- {
- private:
- QSqlQuery *m_query;
- QMutex *m_mutex = NULL;
- public:
- Query(QSqlDatabase &dataBase, QMutex *mutex = NULL);
- Query(Query &&other);
- ~Query(void);
- inline QSqlQuery *operator->(void) { return m_query; }
- inline QSqlQuery *operator*(void) { return m_query; }
- QSqlQuery *takeQuery(void);
- QMutex *takeMutex(void);
- };
- class ConnectNode: public QObject
- {
- Q_OBJECT
- private:
- QSqlDatabase *m_database = NULL;
- QString m_connectionName;
- DatabaseSettings m_dataBaseSettings;
- ConnectSettings m_connectSettings;
- QTimer *m_autoClose = NULL;
- QMutex *m_mutex = NULL;
- public:
- ConnectNode(const DatabaseSettings &dataBaseSettings, const ConnectSettings &connectSettings);
- ~ConnectNode(void);
- public:
- Query query(void);
- public slots:
- bool addDataBase(void);
- void removeDataBase(void);
- bool open(void);
- void close(void);
- signals:
- void controlStartAutoClose(void);
- void controlStopAutoClose(void);
- };
- class Control
- {
- private:
- DatabaseSettings m_databaseSettings;
- ConnectSettings m_connectSettings;
- QMap<qint64, ConnectNode *> m_node;
- QMutex m_mutex;
- QTime *m_wait = NULL;
- public:
- Control(const DatabaseSettings &databaseSettings, const ConnectSettings &connectSettings = ConnectSettings());
- Control(const Control &) = delete;
- ~Control(void);
- public:
- void removeAll(void);
- Query query(void);
- private:
- void insert(const qint64 &key);
- };
- }
- #endif//__JasonQt_Database_h__
JasonQt_Database.cpp
- #include "JasonQt_Database.h"
- using namespace JasonQt_Database;
- // DatabaseSettings
- DatabaseSettings::DatabaseSettings(const DatabaseModeEnum &databastMode, const QString &databaseType, const QString &connectionName)
- {
- m_databaseMode = databastMode;
- m_databaseType = databaseType;
- m_connectionName = connectionName;
- }
- DatabaseSettings::DatabaseSettings(const QString &databaseType, const QString &connectionName, const QString &nameModeName):
- DatabaseSettings(DatabaseNameMode, databaseType, connectionName)
- {
- m_nameModeName = nameModeName;
- }
- DatabaseSettings::DatabaseSettings(const QString &databaseType, const QString &connectionName, const QString &hostModeHostName, const QString &hostModeDatabaseName, const QString &hostModeUserName, const QString &hostModePassword):
- DatabaseSettings(DatabaseHostMode, databaseType, connectionName)
- {
- m_hostModeHostName = hostModeHostName;
- m_hostModeDatabaseName = hostModeDatabaseName;
- m_hostModeUserName = hostModeUserName;
- m_hostModePassword = hostModePassword;
- }
- // ConnectSettings
- ConnectSettings::ConnectSettings(const int &maxOpenTime, const QueryMode &queryMode, const int &minWaitTime)
- {
- m_maxOpenTime = maxOpenTime;
- m_queryMode = queryMode;
- m_minWaitTime = minWaitTime;
- }
- // Query
- Query::Query(QSqlDatabase &dataBase, QMutex *mutex):
- m_query(new QSqlQuery(dataBase))
- {
- m_mutex = mutex;
- }
- Query::Query(Query &&other)
- {
- m_query = other.takeQuery();
- m_mutex = other.takeMutex();
- }
- Query::~Query(void)
- {
- if(m_query)
- {
- delete m_query;
- }
- if(m_mutex)
- {
- m_mutex->unlock();
- }
- }
- QSqlQuery *Query::takeQuery(void)
- {
- auto buf = m_query;
- m_query = NULL;
- return buf;
- }
- QMutex *Query::takeMutex(void)
- {
- auto buf = m_mutex;
- m_mutex = NULL;
- return buf;
- }
- // ConnectNode
- ConnectNode::ConnectNode(const DatabaseSettings &dataBaseSettings, const ConnectSettings &connectSettings):
- m_dataBaseSettings(dataBaseSettings),
- m_connectSettings(connectSettings)
- {
- m_connectionName = QString("%1(%2)").arg(m_dataBaseSettings.connectionName()).arg(QString::number(qint64(QThread::currentThread()), 16));
- m_mutex = new QMutex(QMutex::Recursive);
- if(m_connectSettings.maxOpenTime())
- {
- m_autoClose = new QTimer;
- m_autoClose->setSingleShot(true);
- m_autoClose->setInterval(m_connectSettings.maxOpenTime());
- m_autoClose->moveToThread(qApp->thread());
- m_autoClose->setParent(qApp);
- connect(m_autoClose, SIGNAL(timeout()), this, SLOT(close()), Qt::DirectConnection);
- connect(this, SIGNAL(controlStartAutoClose()), m_autoClose, SLOT(start()));
- connect(this, SIGNAL(controlStopAutoClose()), m_autoClose, SLOT(stop()));
- }
- this->addDataBase();
- }
- ConnectNode::~ConnectNode(void)
- {
- if(m_mutex){ m_mutex->lock(); }
- if(m_autoClose)
- {
- m_autoClose->deleteLater();
- }
- this->removeDataBase();
- if(m_mutex){ m_mutex->unlock(); }
- if(m_mutex){ delete m_mutex; }
- }
- Query ConnectNode::query(void)
- {
- if(!m_database)
- {
- this->addDataBase();
- }
- if(!m_database->isOpen())
- {
- m_database->open();
- }
- if(m_mutex){ m_mutex->lock(); }
- Query buf(*m_database, m_mutex);
- emit controlStartAutoClose();
- return buf;
- }
- bool ConnectNode::addDataBase(void)
- {
- if(m_mutex){ m_mutex->lock(); }
- if(m_database)
- {
- this->removeDataBase();
- }
- m_database = new QSqlDatabase(QSqlDatabase::addDatabase(m_dataBaseSettings.databaseType(), m_connectionName));
- switch(m_dataBaseSettings.databaseMode())
- {
- case DatabaseNameMode:
- {
- m_database->setDatabaseName(m_dataBaseSettings.nameModeName());
- break;
- }
- case DatabaseHostMode:
- {
- m_database->setHostName(m_dataBaseSettings.hostModeHostName());
- m_database->setDatabaseName(m_dataBaseSettings.hostModeDatabaseName());
- m_database->setUserName(m_dataBaseSettings.hostModeUserName());
- m_database->setPassword(m_dataBaseSettings.hostModePassword());
- break;
- }
- default:
- {
- if(m_mutex){ m_mutex->unlock(); }
- return false;
- }
- }
- const auto &&flag = this->open();
- if(m_mutex){ m_mutex->unlock(); }
- return flag;
- }
- void ConnectNode::removeDataBase(void)
- {
- if(m_mutex){ m_mutex->lock(); }
- delete m_database;
- m_database = NULL;
- QSqlDatabase::removeDatabase(m_connectionName);
- if(m_mutex){ m_mutex->unlock(); }
- }
- bool ConnectNode::open(void)
- {
- if(!m_database)
- {
- this->addDataBase();
- }
- if(m_mutex){ m_mutex->lock(); }
- emit controlStartAutoClose();
- const auto &&Flag = m_database->open();
- if(m_mutex){ m_mutex->unlock(); }
- return Flag;
- }
- void ConnectNode::close(void)
- {
- if(m_mutex)
- {
- if(m_mutex->tryLock())
- {
- m_mutex->unlock();
- emit controlStopAutoClose();
- m_database->close();
- }
- else
- {
- emit controlStartAutoClose();
- }
- }
- else
- {
- emit controlStopAutoClose();
- m_database->close();
- }
- }
- // Control
- Control::Control(const DatabaseSettings &databaseSettings, const ConnectSettings &connectSettings):
- m_databaseSettings(databaseSettings),
- m_connectSettings(connectSettings)
- {
- if(m_connectSettings.queryMode() == QueryAutoMode)
- {
- if(databaseSettings.databaseType() == "QMYSQL")
- {
- m_connectSettings.setQueryMode(QueryMultiMode);
- }
- else if(databaseSettings.databaseType() == "QODBC")
- {
- m_connectSettings.setQueryMode(QueryMultiMode);
- }
- else
- {
- m_connectSettings.setQueryMode(QuerySingleMode);
- }
- }
- if(m_connectSettings.queryMode() == QuerySingleMode)
- {
- this->insert(qint64(QThread::currentThread()));
- }
- if(m_connectSettings.minWaitTime() == -1)
- {
- if(databaseSettings.databaseType() == "QMYSQL")
- {
- m_connectSettings.setMinWaitTime(0);
- }
- else if(databaseSettings.databaseType() == "QODBC")
- {
- m_connectSettings.setMinWaitTime(0);
- }
- else
- {
- m_connectSettings.setMinWaitTime(5);
- m_wait = new QTime;
- m_wait->start();
- }
- }
- else
- {
- m_wait = new QTime;
- m_wait->start();
- }
- }
- Control::~Control(void)
- {
- for(auto &now: m_node)
- {
- now->deleteLater();
- }
- if(m_wait)
- {
- delete m_wait;
- }
- }
- void Control::removeAll(void)
- {
- m_mutex.lock();
- for(auto &Now: m_node)
- {
- Now->removeDataBase();
- }
- m_mutex.unlock();
- }
- Query Control::query(void)
- {
- if(m_wait)
- {
- const auto &&flag = m_connectSettings.minWaitTime() - m_wait->elapsed();
- m_wait->restart();
- if(flag > 0)
- {
- QThread::msleep(flag);
- }
- }
- if(m_connectSettings.queryMode() == QueryMultiMode)
- {
- m_mutex.lock();
- const auto &¤tThread = qint64(QThread::currentThread());
- const auto &&now = m_node.find(currentThread);
- if(now != m_node.end())
- {
- auto buf((*now)->query());
- m_mutex.unlock();
- return buf;
- }
- else
- {
- this->insert(qint64(QThread::currentThread()));
- m_mutex.unlock();
- return this->query();
- }
- }
- else
- {
- return (*m_node.begin())->query();
- }
- }
- void Control::insert(const qint64 &key)
- {
- m_node[key] = new ConnectNode(m_databaseSettings, m_connectSettings);
- }
使用:
- // Qt lib import
- #include <QCoreApplication>
- #include <QtConcurrent>
- #include <QSqlError>
- // JasonQt lib import
- #include "JasonQt/JasonQt_Database.h"
- int main(int argc, char *argv[])
- {
- QCoreApplication a(argc, argv);
- /*
- * 注:关于附加参数
- * 这是可以不写的,如果要写的话,可以参考这个:
- *
- * 单次打开数据库最大时间:也就是最大open的时间,对于某些数据库,长时间open但不使用,不仅会造成资源浪费还会意外断开。在设置了60 * 1000后,且60秒内未进行查询,就自动断开。
- * 多线程支持:简单的说就是高级点的数据库,比如 MySql 写 JasonQt_Database::QueryMultiMode ;低级的,比如 Sqlite ,写 JasonQt_Database::QuerySingleMode ,就可以了。
- * 最小等待时间:对于某些数据库,比如Sqlite,密集查询时可能出错,此时可以适当的提升两次查询之间的最小等待时间,比如10ms
- */
- // Sqlite的连接方式 类型 连接名 Sqlite文件路径 单次打开数据库最大时间 多线程支持 最小等待时间
- JasonQt_Database::Control control({ "QSQLITE", "TestDB", "/Users/Jason/test.db" }, { 60 * 1000, JasonQt_Database::QuerySingleMode, 10});
- // MySql的连接方式 类型 连接名 IP 数据库 用户名 密码
- // JasonQt_Database::Control control({ "QMYSQL", "TestDB", "localhost", "JasonDB", "root", "YourPassword" });
- // SqlServer的连接方式 类型 连接名 数据库 数据库名 用户名 密码
- // JasonQt_Database::Control control({ "QODBC", "TestDB", "Driver={SQL SERVER};server=iZ23kn6vmZ\\TEST;database=test;uid=sa;pwd=YourPassword;" });
- auto insert = [&]()
- {
- auto query(control.query()); // 这里的query在解引用( -> 或者 * )后返回的是 QSqlQuery ,直接用就可以了,不需要单独打开数据库或者其他的初始化
- query->prepare("insert into Test1 values(?)"); // 模拟插入操作
- query->addBindValue(rand() % 1280);
- if(!query->exec())
- {
- qDebug() << "Error" << __LINE__;
- }
- query->clear();
- query->prepare("insert into Test2 values(NULL, ?, ?)");
- query->addBindValue(rand() % 1280);
- QString buf;
- for(int now = 0; now < 50; now++)
- {
- buf.append('a' + (rand() % 26));
- }
- query->addBindValue(buf);
- if(!query->exec())
- {
- qDebug() << "Error" << __LINE__;
- }
- };
- auto delete_ = [&]()
- {
- auto query(control.query());
- query->prepare("delete from Test1 where data = ?");
- query->addBindValue(rand() % 1280);
- if(!query->exec())
- {
- qDebug() << "Error" << __LINE__;
- }
- query->clear();
- query->prepare("delete from Test2 where data1 = ?");
- query->addBindValue(rand() % 1280);
- if(!query->exec())
- {
- qDebug() << "Error" << __LINE__;
- }
- };
- auto update = [&]()
- {
- auto query(control.query());
- query->prepare("update Test1 set data = ? where data = ?");
- query->addBindValue(rand() % 1280);
- query->addBindValue(rand() % 1280);
- if(!query->exec())
- {
- qDebug() << "Error" << __LINE__;
- }
- query->clear();
- query->prepare("update Test2 set data1 = ?, data2 = ? where data1 = ?");
- query->addBindValue(rand() % 1280 + 1);
- QString buf;
- for(int now = 0; now < 50; now++)
- {
- buf.append('a' + (rand() % 26));
- }
- query->addBindValue(buf);
- query->addBindValue(rand() % 1280 + 1);
- if(!query->exec())
- {
- qDebug() << "Error" << __LINE__;
- }
- };
- auto select = [&]()
- {
- auto query(control.query());
- query->prepare("select * from Test1 where data = ?");
- query->addBindValue(rand() % 1280);
- if(!query->exec())
- {
- qDebug() << "Error" << __LINE__;
- }
- query->clear();
- query->prepare("select * from Test2 where data1 = ?");
- query->addBindValue(rand() % 1280);
- if(!query->exec())
- {
- qDebug() << "Error" << __LINE__;
- }
- };
- volatile int count = 0, last = 0;
- QTime time;
- time.start();
- QThreadPool::globalInstance()->setMaxThreadCount(10);
- for(int now = 0; now < 3; now++) // 开启3个线程测试
- {
- QtConcurrent::run([&]()
- {
- while(true)
- {
- count++;
- if(!(count % 1000))
- {
- const auto &&now = time.elapsed();
- qDebug() << now - last; // 打印每完成1000语句的时间
- last = now;
- }
- switch(rand() % 20)
- {
- case 0: { insert(); break; }
- case 1: { delete_(); break; }
- case 2: { update(); break; }
- default: { select(); break; }
- }
- }
- QThread::msleep(10);
- });
- }
- return a.exec();
- }
我也写了一个示例工程,可以前往这里下载
http://download.csdn.net/detail/wsj18808050/8566497
http://blog.csdn.net/wsj18808050/article/details/44891715
QSqlDatabase的进一步封装(多线程支持+更加简单的操作)——同时支持MySQL, SQL Server和Sqlite的更多相关文章
- 功能齐全、效率一流的免费开源数据库导入导出工具(c#开发,支持SQL server、SQLite、ACCESS三种数据库),每月借此处理数据5G以上
软件名:DataPie 功能:支持SQL server.SQLite.ACCESS数据库的导入.导出.存储过程调用,支持EXCEL2007.EXCEL2003.ACCESS2007. CSV文件导入数 ...
- 查询获取所有数据库名及数据库中表的集合、数据库连接字符串(类生成器,暂时支持mysql,sql server,后期有oracle再更新)
现所在公司做项目开发时,经常会自己创建model类,网上的生成器也很多,完全满足自己的不太现实,所以感觉自己做一个更有底气,主要针对过程中的一些语句进行整理,也供其他人学习参考. 连接字符串: mys ...
- 最简单 无返回值 无参数 sql server存储过程
CREATE proc Upadte_stateas update Table_1 set [state]=2 where id in (select id from Table_1 where st ...
- SQL Server 2016原生支持JSON
转载原地址: http://www.cnblogs.com/lyhabc/p/4747694.html SQL Server 2005 开始支持 XML 数据类型,提供原生的 XML数据类型.XML ...
- 自动化安装SQL Server+SP就那么简单
随着业务.企业规模的日益壮大,DB的数量也在不断增多,配置一台新增DB,从服务器的参数配置,磁盘阵列规划,DB安装部署,DB参数调优等等一列步骤下来,手工操作的效率变得越来越低,因为我负责的数据库近些 ...
- 动化安装SQL Server+SP就那么简单
随着业务.企业规模的日益壮大,DB的数量也在不断增多,配置一台新增DB,从服务器的参数配置,磁盘阵列规划,DB安装部署,DB参数调优等等一列步骤下来,手工操作的效率变得越来越低,因为我负责的数据库近些 ...
- Microsoft SQL Server JDBC 驱动程序支持矩阵
本页包含 Microsoft SQL Server JDBC 驱动程序的支持矩阵和支持生命周期策略. Microsoft JDBC 驱动程序支持生命周期矩阵和策略 Microsoft 支持生命周期 ( ...
- YxdJSON - Delphi 高性能 JSON 库(支持RTTI和序列化操作)
源:YxdJSON - Delphi 高性能 JSON 库(支持RTTI和序列化操作) Delphi 高性能 JSON 库(支持RTTI和序列化操作) 支持平台: Windows, Android, ...
- SQL Server On Linux:基于实际项目案例,总结功能支持情况及相关问题解决方案,讲如何快速完成迁移
上个月,有个朋友问我说Sql Sever向Mysql迁移有什么好的经验分享,他们公司客户明确提出不再提供Windows服务器,现在计划Mysql迁移.我说Mysql迁移成本太高了,不妨可以了解一下SQ ...
随机推荐
- Web应用的部署
本文将介绍一些Web应用的部署: 部署规则 要成功地部署一个Web应用,必须遵循以下目录结构. 1.WEB-INF一定要直接放到应用上下文(Webapp)之下. 2.classes目录必须直接放在WE ...
- MySQL常用命令及操作
1.登录与退出 1)登录 windows下直接在DOS命令窗口用root用户登录输入mysql回车; linux下输入使用PUTTY连接mysql的服务器,然后输入: ...
- 10个你必须知道的jQueryMobile代码片段
1.在列表项和按钮上禁用文本截断 如果你的列表项或者按钮上是一个很长的文本,它将会被jQuery Mobile自动截断,要禁用这个截断设置,需要在CSS选择器上添加属性"white- ...
- 点击超链接执行js代码实现确认操作
如题,本次是要实现点击超链接实现执行js代码,并确认是否删除数据库数据,采用php. 首先链接数据库,查询数据库数据: 1: <?php 2: $dbms='mysql'; //数据库类型 ,对 ...
- Java之线程的生命周期
在Java中,线程有5中不同状态,分别是:新建(New).就绪(Runable).运行(Running).阻塞(Blocked)和死亡(Dead).它们之间的转换图如下: 上图有一个例外,调用yiel ...
- WPS Office手机版调用接口代码指导帖之一(Android)
经常会有一些喜欢开发鼓捣的童鞋问我们,WPS Office手机版是否提供调用接口,希望在android中使用一个调用命令,直接调用WPS手机版来打开指定的DOC文件,而不用弹出一个程序可选列表(如果用 ...
- Delphi代码中嵌入ASM代码
前言 Delphi作为一个快速高效的开发平台,使用的人越来越多,但熟悉在Delphi代码中嵌入ASM代码的程序员我想不多,因为这方面的资料太少了,另一方面,它还需要有基本的汇编语言知识,关於汇编语言的 ...
- linux下监视进程 崩溃挂掉后自动重启的shell脚本
如何保证服务一直运行?如何保证即使服务挂掉了也能自动重启?在写服务程序时经常会碰到这样的问题.在Linux系统中,强大的shell就可以很灵活的处理这样的事务. 下面的shell通过一个while-d ...
- vc++深入跟踪MFC程序的执行流程
在MFC程序设计的学习过程中最令人感到难受,甚至于有时会动摇学习者信心的就是一种对于程序的一切细节都没有控制权的感觉.这种感觉来源于学习者不知道一个MFC程序是如何运行起来的(即一个MFC程序的执行流 ...
- Mactype 解决字体出现剃尾
使用mactype之后, 发现windows字体的效果改善了好多.但作为程序员, 天天和各种文本工具打交道.最近发现PHPStorm中的有些等宽字体会出现剃尾的现象.特别是 {} [] ()这些字符, ...