0
点赞
收藏
分享

微信扫一扫

Qt之访问SQLite数据库


Qt 通过不同的数据库驱动来实现访问不同的数据库,QSqlDriver是一个抽象类,是所有数据库驱动类的基类。
Qt 支持访问很多不同的数据库,例如 Sqlite, MySQL, SqlServer 等,但是 Qt 具体都支持哪些数据库呢?
在Qt Assistant中输入QSqlDatabase,可以看到Qt 目前支持的所有数据库:

Qt之访问SQLite数据库_Qt


但是并不代表在我们的程序里就可以直接使用代码访问这些数据库了,这里的所谓支持,是指 Qt 提供了访问这些数据库的 插件的代码,其中有些已经编译成了可以直接使用的插件,有的没有编译。如果想要访问的数据库不包含在里面,我们就需要按照 Qt 的规范去开发数据库驱动插件,至于怎么做可以在Qt Assistant里搜索SQL Database Drivers,可以找到How to Write Your Own Database Driver。

那么有哪些数据库插件已经编译好了可以直接使用呢?

在plugins/sqldrivers目录中列出了所有编译好的数据库插件,如下图所示:

Qt之访问SQLite数据库_数据库_02


qDebug() << QSqlDatabase::drivers(),输出: ("QSQLITE", "QMYSQL", "QMYSQL3", "QODBC", "QODBC3", "QPSQL", "QPSQL7"),说明访问 Sqlite, MySql, MySql3, ODBC、ODBC3、PostgreSql, PostgreSql7 等不需要自己编译驱动插件,但是如果想访问SqlServer的话,就得自己编译驱动了。

例如我们想访问Oracle,Qt已经提供了Oracle驱动插件的代码,但是在plugins/sqldrivers目录里并没有其编译好的可用插件,那么我们就需要自己去编译驱动插件了。编译的方法可以在Qt Assistant里搜索SQL Database Drivers,找到Building the Drivers

按照Qt Assistant里的说明也不一定就能编译成功,此时只能在网上搜索看有没有其他人遇到同样的问题。

一.为什么要用 SQLite?

☆不需要一个单独的服务器进程或操作的系统(无服务器的)。
☆SQLite 不需要配置,这意味着不需要安装或管理。
☆一个完整的 SQLite 数据库是存储在一个单一的跨平台的磁盘文件。
☆SQLite 是非常小的,是轻量级的,它的设计目标是嵌入式的,而且已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。
☆SQLite 是自给自足的,这意味着不需要任何外部的依赖。
☆SQLite 事务是完全兼容 ACID 的,允许从多个进程或线程安全访问。
☆SQLite 支持 SQL92(SQL2)标准的大多数查询语言的功能。
☆SQLite 使用 ANSI-C 编写的,并提供了简单和易于使用的 API, 支持多种开发语言,C, C++, PHP, Perl, Java, C#,Python, Ruby等
☆SQLite 可在 UNIX(Linux, Mac OS-X, Android, iOS)和 Windows(Win32, WinCE, WinRT)中运行。 

 二.SQLite常用操作

下图是模拟登陆账号数据库操作的效果展示,实现了常用的增、删、改、查,QTableWidget中是在各种操作后,查询数据库得到的结果。

Qt之访问SQLite数据库_QSqlQuery_03


一些定义

const QString COUNT_OF_ACCOUNT_TBL = "SELECT COUNT(*) FROM account_tbl";
const QString DROP_ACCOUNT_TBL = "DROP TABLE account_tbl";
const QString CREATE_ACCOUNT_TBL =
"CREATE TABLE IF NOT EXISTS account_tbl "
"("
" id INTEGER PRIMARY KEY,"
" userId TEXT DEFAULT '',"
" userName TEXT DEFAULT '',"
" nickName TEXT DEFAULT '',"
" portrait TEXT DEFAULT '',"
" loginTime TEXT DEFAULT '',"
" isVip INTEGER DEFAULT 0"
");";
const QString INSERT_ACCOUNT_TBL = "INSERT OR REPLACE INTO account_tbl("
"userId,userName,nickName,portrait,loginTime,isVip) "
"VALUES(?,?,?,?,?,?);";
const QString DELETE_ACCOUNT_TBL = "DELETE FROM account_tbl WHERE userId=:userId;";
const QString UPDATE_ACCOUNT_TBL = "UPDATE account_tbl SET nickName=:nickName,isVip=:isVip WHERE userId=:userId;";
const QString QUERY_ACCOUNT_TBL = "SELECT * FROM account_tbl WHERE isVip=:isVip;";
const QString QUERY_ACCOUNT_TBL_2 = "SELECT * FROM account_tbl ORDER BY id ASC LIMIT ? OFFSET ?;";

1.打开数据库、关闭数据库、创建表和删除表

bool QHDBManager::openDB(const QString &dbPath)
{
m_database.setDatabaseName(dbPath);
if (m_database.isOpen())
{
return true;
}
if (!m_database.open())
{
qDebug() << "DB Open Error:" << m_database.lastError();
return false;
}
return true;
}

void QHDBManager::closeDB()
{
m_database.close();
}

bool QHDBManager::createTables()
{
if (!m_database.tables().contains("account_tbl"))
{
m_sqlQuery.prepare(CREATE_ACCOUNT_TBL);
if (!m_sqlQuery.exec())
{
qDebug() << "Account Table Create Error:" << m_sqlQuery.lastError();
return false;
}
}

return true;
}

bool QHDBManager::dropTables()
{
if (m_database.tables().contains("account_tbl"))
{
m_sqlQuery.prepare(DROP_ACCOUNT_TBL);
if (!m_sqlQuery.exec())
{
qDebug() << "Account Table Drop Error:" << m_sqlQuery.lastError();
return false;
}
}

return true;
}

2.增

void QHDBManager::insertAccount(const QVariantMap &data)
{
if (!m_dbOpened)
{
return;
}
m_sqlQuery.prepare(INSERT_ACCOUNT_TBL);

m_sqlQuery.addBindValue(data["userId"]);
m_sqlQuery.addBindValue(data["userName"]);
m_sqlQuery.addBindValue(data["nickName"]);
m_sqlQuery.addBindValue(data["portrait"]);
m_sqlQuery.addBindValue(data["loginTime"]);
m_sqlQuery.addBindValue(data["isVip"]);

if (!m_sqlQuery.exec())
{
qDebug() << "Account Data Insert Error:" << m_sqlQuery.lastError();
}
}

如果要一次添加多条数据,使用普通的INSERT语句循环插入会比较耗时,此时可以使用事务(Transaction)特性加速数据库访问。
Qt 里事物相关的函数:
是否支持事务:bool QSqlDriver::hasFeature(QSqlDriver::Transactions) const,返回 true 表示支持事务,返回 false 表示不支持事务
开启事务:bool QSqlDatabase::​transaction()
提交事务:bool QSqlDatabase::​commit()
回滚事务:bool QSqlDatabase::rollback()
具体代码如下:

void QHDBManager::insertAccount(const QVariantList &dataList)
{
if (!m_dbOpened)
{
return;
}
m_database.transaction();
foreach (QVariant v, dataList)
{
QVariantMap data=v.toMap();

m_sqlQuery.prepare(INSERT_ACCOUNT_TBL);

m_sqlQuery.addBindValue(data["userId"]);
m_sqlQuery.addBindValue(data["userName"]);
m_sqlQuery.addBindValue(data["nickName"]);
m_sqlQuery.addBindValue(data["portrait"]);
m_sqlQuery.addBindValue(data["loginTime"]);
m_sqlQuery.addBindValue(data["isVip"]);

if (!m_sqlQuery.exec())
{
qDebug() << "Account Data Insert Error:" << m_sqlQuery.lastError();
}

insertAccount(data);
}
m_database.commit();
}

3.删

void QHDBManager::deleteAccount(const QString &userId)
{
if (!m_dbOpened)
{
return;
}
m_sqlQuery.prepare(DELETE_ACCOUNT_TBL);
m_sqlQuery.bindValue(":userId",userId);

if (!m_sqlQuery.exec())
{
qDebug() << "Delete Data Update Error:" << m_sqlQuery.lastError();
}
}

4.改

void QHDBManager::updateAccount(const QVariantMap &data)
{
if (!m_dbOpened)
{
return;
}
m_sqlQuery.prepare(UPDATE_ACCOUNT_TBL);
m_sqlQuery.bindValue(":nickName",data["nickName"]);
m_sqlQuery.bindValue(":isVip",data["isVip"]);
m_sqlQuery.bindValue(":userId",data["userId"]);

if (!m_sqlQuery.exec())
{
qDebug() << "Account Data Update Error:" << m_sqlQuery.lastError();
}
}

5.查

5.1精准查询

QVariantList QHDBManager::queryAccount(int isVip)
{
QVariantList allData;
if (!m_dbOpened)
{
return allData;
}
m_sqlQuery.prepare(QUERY_ACCOUNT_TBL);
m_sqlQuery.bindValue(":isVip",isVip);

if (!m_sqlQuery.exec())
{
qDebug() << "Account Data Query Error:" << m_sqlQuery.lastError();
return allData;
}
else
{
while(m_sqlQuery.next())
{
QVariantMap varMap;
varMap["userId"]=m_sqlQuery.value(1);
varMap["userName"]=m_sqlQuery.value(2);
varMap["nickName"]=m_sqlQuery.value(3);
varMap["portrait"]=m_sqlQuery.value(4);
varMap["loginTime"]=m_sqlQuery.value(5);
varMap["isVip"]=m_sqlQuery.value(6);

QVariant tempData(varMap);
allData.append(tempData);
}
}

return allData;
}

5.2分组查询

QVariantList QHDBManager::queryAccount(int pageIndex, int rowCount)
{
QVariantList allData;
if (!m_dbOpened)
{
return allData;
}
m_sqlQuery.prepare(QUERY_ACCOUNT_TBL_2);
m_sqlQuery.addBindValue(rowCount);
m_sqlQuery.addBindValue(pageIndex*rowCount);
if (!m_sqlQuery.exec())
{
qDebug() << "Account Data Query Error:" << m_sqlQuery.lastError();
return allData;
}
else
{
while(m_sqlQuery.next())
{
QVariantMap varMap;
varMap["userId"]=m_sqlQuery.value(1);
varMap["userName"]=m_sqlQuery.value(2);
varMap["nickName"]=m_sqlQuery.value(3);
varMap["portrait"]=m_sqlQuery.value(4);
varMap["loginTime"]=m_sqlQuery.value(5);
varMap["isVip"]=m_sqlQuery.value(6);

QVariant tempData(varMap);
allData.append(tempData);
}
}

return allData;
}

5.3模糊查询
这里举个例子

query.prepare("SELECT * FROM user WHERE username LIKE :match");
query.bindValue(":match", "%o%");

6.获取总行数

int QHDBManager::getAccountCount()
{
if (!m_dbOpened)
{
return 0;
}

m_sqlQuery.prepare(COUNT_OF_ACCOUNT_TBL);
if (!m_sqlQuery.exec())
{
qDebug() << "Account Data Count Error:" << m_sqlQuery.lastError();
return 0;
}
else
{
while(m_sqlQuery.next())
{
return m_sqlQuery.value(0).toInt();
}
}

return 0;
}

获取总行数还是比较实用的,结合总行数和分组查询,可以获取数据表中的所有数据

int totalCount = theDBManager->getAccountCount();
QVariantList dataList = theDBManager->queryAccount(0,totalCount);

举报

相关推荐

0 条评论