Qt对数据库的简单操作
1.问:数据库的操作一般是指什么?
答:我觉得任何一门语言对数据库的简单操作无非就是增、删、查、改等,入门一般都是使用SQL语句来操作数据库,当然使用SQL语句操作数据库的一大弊端就是,如果数据量大的话就会造成时间成本的剧增(如果使用单线程的话还会造成界面的卡死如果有界面的话);所以对于数据量大的存储,我觉得如果不使用多线程的话,尽量使用存储过程实现对数据库的操作。
2.问:Qt对数据库怎么操作?
答:这里只讲述简单的操作,所以我使用的也是SQL语句,而在项目中一般都会讲究mvc的思想,没有mvc的思想,自己写的代码两个月后来看只有一种感觉,我靠,这是谁写的代码,这么烂。而你自己也看不懂自己的代码,C++中类的出现使我们能够更好的管理我们的代码,写出复用性强,功能明确,分工也很明确的代码,因此,在这里,我也是将对数据库的操作封装成类,在以后使用的过程中,只是简单的copy几个文件的问题,再修改一下数据库表中的字段就很容易的实现了,节省大量的时间。
3.问:具体的实现?
答:先讲一下结构,我是将对数据库的操作单独封装成类,将读表和写表的过程再分别封装成类,这样就会很明确自己的步骤。并可以通过读配置文件的信息对数据库进行设置。看一下具体实现吧。
首先是对数据库设置名称,写代码写注释是一个很好的习惯,不要让别人看不懂你的代码。。
首先看看数据库表结构,我这里是操作了多张表
【Qt对数据库的简单操作】_rowid | FileName | FilePath | FileType | FileSize | FileTime |
1 | test.txt | C:\text | 文件 | 20 kb | 2106-12-17 10:21:56 |
2 | test.ini | D:\workspace\test | 文件 | 58 kb | 2106-12-17 10:21:56 |
3 | work | D:\workspace\test | 文件夹 | 0 kb | 2106-12-17 10:21:56 |
定义一些可以用到的变量
QSqlDatabase *pDb;
QSqlQuery *pQuery;
//连接名
QString connName;
//数据库文件
QString fileDb;
/*******************************************
* creator: @ji
* function: 设置数据库名称
* Date: 2016-09-13
* parameter: 数据库名称
********************************************/
bool QDBHelpe::setDBName(QString str_DBName)
{
try{
fileDb = str_DBName;
return true;
}
catch(...)
{
return false;
}
}
接下来解释千篇一律的打开数据库,关闭数据库等等。。
/*******************************************
* creator: @ji
* function: 打开数据库连接
* Date: 2016-09-13
* parameter:
********************************************/
int QDBHelpe::openDB()
{
try
{
if (pDb)
{
closeDB();
}
pDb = new QSqlDatabase();
//防止重复打开同名连接
if(QSqlDatabase::contains(connName))
*pDb = QSqlDatabase::database(connName);
else
*pDb = QSqlDatabase::addDatabase("QSQLITE", connName);
pDb->setDatabaseName(fileDb);
if (pDb->open())
{
if (pQuery)
{
delete pQuery;
pQuery = NULL;
}
pQuery = new QSqlQuery(*pDb);
return 0;
}
return -1;
}
catch (...)
{
return -1;
}
}
/*******************************************
* creator: @ji
* function: 关闭数据库连接
* Date: 2016-09-13
* parameter: 串口信息
********************************************/
void QDBHelpe::closeDB()
{
try
{
if (pQuery)
{
delete pQuery;
pQuery = NULL;
}
if (pDb && pDb->isOpen())
{
pDb->close();
delete pDb;
pDb = NULL;
}
//从列表中移除连接
QSqlDatabase::removeDatabase(connName);
}
catch (...) {}
}
/*******************************************
* creator: @ji
* function: 执行sql语句
* Date: 2016-09-13
* parameter: 需要执行的sql语句
********************************************/
bool QDBHelpe::executeSql(QString sql)
{
try
{
openDB();
QSqlQuery q(*pDb);
bool ret = q.exec(sql);
closeDB();
qDebug()<<"ret = "<exec(sql);
if (!pCount)
return pQuery;
//获取记录数目
if (pDb->driver()->hasFeature(QSqlDriver::QuerySize))
{
*pCount =pQuery->size();
}
else
{
pQuery->last();
*pCount = pQuery->at()+1;
//回到第一条记录的前面
pQuery->seek(-1);
}
return pQuery;
}
catch (...)
{
return NULL;
}
}
/*******************************************
* creator: @ji
* function: 开始事物处理
* Date: 2016-09-13
* parameter:
********************************************/
void QDBHelpe::startTransaction()
{
openDB();
QSqlDatabase::database(connName).transaction();
}/*******************************************
* creator: @ji
* function: 执行事物处理
* Date: 2016-09-13
* parameter: sql语句
********************************************/
void QDBHelpe::executeBatch(QString sql)
{
pQuery->exec(sql);
}
/*******************************************
* creator: @ji
* function: 结束事物处理
* Date: 2016-09-13
* parameter: bool型值
********************************************/
void QDBHelpe::endTransaction(bool isOK)
{
if (isOK)
QSqlDatabase::database(connName).commit();
else
QSqlDatabase::database(connName).rollback();
closeDB();
}
4.问:这只是对数据库的操作,对表的读写要怎么实现?
答:对表的读写我发现了一个很好用的东西,使用jsonobject类可以对表的字段进行序列化和反序列化,jsonobject类是在Qt5以后才出现的工具,以前在用Qt4的时候,也是很苦逼的在自己一行一行写SQL语句。对于表数据的读取详细见下:
/*****************sQLReadHelp.h****************************/
class sQLReadHelp
{
public:
sQLReadHelp();
void read(const QJsonObject &json);
void write(QJsonObject &json) const;
sQLReadHelp* getModel(QSqlQuery& query);
virtual QList* getFileList(QString strsql);
virtual QList* getList(QString strWhere,QString strTableName);
public:
QString m_FileName;
QString m_FilePath;
QString m_FileType;
QString m_FileSize;
QString m_FileTime;
};
上面定义的5个QString类型的字符串对应的就是表里面的字段,这些字段当然可以根据自己具体的表字段进行设置。
/*******************************************
* creator: @ji
* function: 反序列化
* Date: 2016-09-13
* parameter:
*******************************************/
void sQLReadHelp::read(const QJsonObject &json)
{
m_FileName= json["FileName"].toString();
m_FilePath= json["FilePath"].toString();
m_FileType= json["FileType"].toString();
m_FileSize= json["FileSize"].toString();
m_FileTime= json["FileTime"].toString();
}
/*******************************************
* creator: @ji
* function: 序列化
* Date: 2016-09-13
* parameter:
*******************************************/
void sQLReadHelp::write(QJsonObject &json) const
{
json["FileName"]= m_FileName;
json["FilePath"]= m_FilePath;
json["FileType"]= m_FileType;
json["FileSize"]= m_FileSize;
json["FileTime"]= m_FileTime;
}
反序列化和序列化就是将表中的字段值和QString字符串的相互转换。
读表的过程通常需要是将表里面的某一些数据全部读出来,所以我这里实现了获取表中的多行数据,单行数据的获取我没有实现,如果需要,可以自行实现。
/*******************************************
* creator: @ji
* function: 获取表单数据列表
* Date: 2016-09-13
* parameter: 数据库查询条件数据库名
*******************************************/
QList* sQLReadHelp::getList(QString strWhere,QString strTableName)
{
QSqlQuery* query = NULL;
QList* pCheckList = new QList();
if (strWhere.trimmed() != "")
{
strWhere = " where " + strWhere;
}
try
{
QString sql = QString("select * from %1 %2")
.arg(strTableName)
.arg(strWhere);
int num = 0;
query = g_pQDBHeper->getDataSet(sql, &num);
for (int i=0;
i < num;
i++)
{
sQLReadHelp *pWrite = getModel(*query);
if(pWrite != NULL)
{
pCheckList->append(pWrite);
}
}
g_pQDBHeper->closeDB();
return pCheckList;
}
catch(...)
{
if (query)
{
g_pQDBHeper->closeDB();
query = NULL;
}
if (pCheckList)
{
//释放内部QcPlan指针
qDeleteAll(*pCheckList);
pCheckList->clear();
delete pCheckList;
}
}
return NULL;
}
而获取列表的前提是获取一行数据,
/*******************************************
* creator: @ji
* function: 获取一个对象实体
* Date: 2016-09-13
* parameter: 表单获取数据集指针
*******************************************/
sQLReadHelp* sQLReadHelp::getModel(QSqlQuery& query)
{
sQLReadHelp *pWrite = NULL;
try
{
if (query.next())
{
pWrite = new sQLReadHelp();
pWrite->m_FileName = query.value("FileName").toString();
pWrite->m_FilePath = query.value("FilePath").toString();
pWrite->m_FileType = query.value("FileType").toString();
pWrite->m_FileSize = query.value("FileSize").toString();
pWrite->m_FileTime = query.value("FileTime").toString();
return pWrite;
}
return NULL;
}
catch(...)
{
if (pWrite)
delete pWrite;
return NULL;
}
}
至此,对于表的读操作基本已经完成
5.问:那么写表呢?
答:写表和读表的过程基本是一样的,看看具体实现吧。
/**************************sQLWriteHelp.h*************************************/
class sQLWriteHelp
{
public:
sQLWriteHelp();
/**具体的函数会在cpp文件中讲到*/
public:
/**这些字段对应表中的字段*/
QString m_FileName;
QString m_FilePath;
QString m_FileType;
QString m_FileSize;
QString m_FileTime;
private:
QString m_TableName;
};
序列化和反序列和读表的一模一样,这里就不在啰嗦了;获取更新表单和插入表单的SQL语句,说简单点就是一个重组SQL语句的过程。
/*******************************************
* creator: @ji
* function: 获取更新表单sql语句
* Date: 2016-09-13
* parameter: 数据类指针 sql查询条件
*******************************************/
QString sQLWriteHelp::getUpdateStr(sQLWriteHelp* p, QString strWhere)
{
QString sql = QString("update %1 set ").arg(m_TableName);
sql += "FileName='" + p->m_FileName + "',";
sql += "FilePath='" + p->m_FilePath + "',";
sql += "FileType='" + p->m_FileType + "',";
sql += "FileSize='" + p->m_FileSize + "',";
sql += "FileTime='" + p->m_FileTime + "'";
if (strWhere != "")
sql += " where " + strWhere;
else
sql += " where FileName='" + p->m_FileName + "'";
return sql;
}
/*******************************************
* creator: @ji
* function: 获取插入表单sql语句
* Date: 2016-09-13
* parameter: 数据类指针 sql查询条件
*******************************************/
QString sQLWriteHelp::getInsertStr(sQLWriteHelp* p)
{
QString sql = QString("insert into %1 (FileName,FilePath,FileType,FileSize,FileTime) values (")
.arg(m_TableName);
sql += "'" + p->m_FileName + "',";
sql += "'" + p->m_FilePath + "',";
sql += "'" + p->m_FileType + "',";
sql += "'" + p->m_FileSize + "',";
sql += "'" + p->m_FileTime + "'";
sql += ")";
return sql;
}
判断表单是否存在某条记录,可以根据自己的需求选择是一个条件还是多个条件,我这里是因为同名文件可能存在于不同的文件夹,所以选择了判断两个字段。
/*******************************************
* creator: @ji
* function: 判断表单是否存在记录
* Date: 2016-09-13
* parameter: 查询条件
*******************************************/
bool sQLWriteHelp::exist(QString strFileName,QString strFilePath)
{
try
{
QString strSql = QString("select count(1) from %1 where FileName='%2' and FilePath='%3'")
.arg(m_TableName).arg(strFileName).arg(strFilePath);
QSqlQuery *pQuery = g_pQDBHeper->getDataSet(C_STR(strSql), NULL);
bool ret = false;
if (pQuery->next())
{
ret = (pQuery->value(0).toInt() > 0) ? true : false;
}
g_pQDBHeper->closeDB();
return ret;
}
catch (...)
{
return false;
}
}
表单增加一个数据就是传入一个数据指针再解析的过程,然后插入数据库
/*******************************************
* creator: @ji
* function: 表单增加一条数据
* Date: 2016-09-13
* parameter: 数据类指针表名称
*******************************************/
bool sQLWriteHelp::add(sQLWriteHelp* model,QString strTableName)
{
try
{
this->setTableName(strTableName);
QString strwhere;
strwhere = "";
if (exist(model->m_FileName,model->m_FilePath))
{
update(model,strwhere);
return true;
}
QString sql = getInsertStr(model);
return g_pQDBHeper->executeSql(sql);
}
catch (...)
{
return false;
}
}
/*******************************************
* creator: @ji
* function: 表单更新数据
* Date: 2016-09-13
* parameter: 数据类指针 sql查询条件
*******************************************/
bool sQLWriteHelp::update(sQLWriteHelp* model, QString strWhere)
{
try
{
QString sql = getUpdateStr(model,strWhere);
return g_pQDBHeper->executeSql(sql);
}
catch(...)
{
return false;
}
}
清空一张表,因为我这里表里面设置了第一列行号的自增功能,所以清空后需要将语气关联的记录该表行号的另一张表数据置0操作。
/*******************************************
* creator: @ji
* function: 清空一张表数据
* Date: 2016-12-08
* parameter: 表名称
*******************************************/
bool sQLWriteHelp::deleteTableAllData(QString strTableName)
{
QString sql = QString("delete from %1").arg(strTableName);
g_pQDBHeper->executeSql(sql);
QString sql2 = QString("update sqlite_sequence SET seq = 0 where name ='%1'").arg(strTableName);
return g_pQDBHeper->executeSql(sql2);
}
/*******************************************
* creator: @ji
* function: 将一张表的数据完全覆盖另一张表
* Date: 2016-12-08
* parameter: 表名称
*******************************************/
bool sQLWriteHelp::copyTB2ToTB1(QString strTableName1,QString strTableName2)
{
QString sql = QString("insert into %1 select * from %2").arg(strTableName1).arg(strTableName2);
return g_pQDBHeper->executeSql(sql);
}
6.问:封装好之后我们需要怎么具体的调用?
答:所以接下来我就要简单的讲讲具体的调用方法,首先看看插入数据
/**首先new一个写表的指针出来**/
sQLWriteHelp *model = new sQLWriteHelp();
/**接下来解释将数据赋值给指针的每一项**/
model->m_FileName = QString("生在90后的60后的专栏.ini");
model->m_FilePath = QSting("C:\xxx\xxx");
model->m_FileType = QString("文件");
model->m_FileSize = QString::number(520) + "kb";
model->m_FileTime = QString("2016-12-17");
/**调用插入标的函数就可以了**/
g_pSQLwriteHelp->add(model,m_strTableName);
从数据库获取列表
/********************************************************
* creator: @ji
* function: 从数据库中获取文件列表
* Date: 2016-12-08
* parameter:
* ******************************************************/
QList* FileSerch::getFileList(QString sql,QString strTableName)
{
QList* m_pCheckList;
m_pCheckList = g_pSQLreadHelp->getList(sql,strTableName);
return m_pCheckList;
}
至此,Qt对数据库的简单操作基本就已经完成了,欢迎大家交流学习,分享就是进步。。。
推荐阅读
- 热闹中的孤独
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 布丽吉特,人生绝对的赢家
- 慢慢的美丽
- 尽力
- 一个小故事,我的思考。
- 家乡的那条小河
- Docker应用:容器间通信与Mariadb数据库主从复制