Qt操作SQLite數(shù)據(jù)庫的教程詳解
0.前言
SQLite是一款開源、輕量級、跨平臺的數(shù)據(jù)庫,無需server,無需安裝和管理配置。它的設(shè)計目標(biāo)是嵌入式的,所以很適合小型應(yīng)用,也是Qt應(yīng)用開發(fā)種常用的一種數(shù)據(jù)庫。
1.驅(qū)動
Qt SQL模塊使用驅(qū)動程序插件(plugins)與不同的數(shù)據(jù)庫API進(jìn)行通信。由于Qt的SQL模塊API與數(shù)據(jù)庫無關(guān),因此所有特定于數(shù)據(jù)庫的代碼都包含在這些驅(qū)動程序中。Qt提供了幾個驅(qū)動程序,也可以添加其他驅(qū)動程序。提供驅(qū)動程序源代碼,可用作編寫自己的驅(qū)動程序的模型。
QtCreator在*.pro中引入sql模塊(QT+=sql),或是VS中在Qt VS Tool里勾選上sql模塊,就可以使用該模塊的接口了。
可以使用QSqlDatabase::drivers()獲取驅(qū)動程序列表并打印,Qt5.9.7輸出如下:
其中,SQLite是一個進(jìn)程內(nèi)數(shù)據(jù)庫,這意味著沒有必要擁有數(shù)據(jù)庫服務(wù)器。SQLite在單個文件上運行,在打開連接時必須將其設(shè)置為數(shù)據(jù)庫名稱。如果該文件不存在,SQLite將嘗試創(chuàng)建它。。
2.初相遇
/*
* ... ...
* 我喜歡那樣的夢
* 在夢里 一切都可以重新開始
* 一切都可以慢慢解釋
* 心里甚至還能感覺到所有被浪費的時光
* 竟然都能重回時的狂喜和感激
* ... ...
*
* ----席慕容《初相遇》
*/
#include <QSqlDatabase>
#include <QDebug>
void initDb()
{
//qDebug()<<QSqlDatabase::drivers();//打印驅(qū)動列表
QSqlDatabase db;
//檢測已連接的方式 - 默認(rèn)連接名
//QSqlDatabase::contains(QSqlDatabase::defaultConnection)
if(QSqlDatabase::contains("qt_sql_default_connection"))
db = QSqlDatabase::database("qt_sql_default_connection");
else
db = QSqlDatabase::addDatabase("QSQLITE");
//檢測已連接的方式 - 自定義連接名
/*if(QSqlDatabase::contains("mysql_connection"))
db = QSqlDatabase::database("mysql_connection");
else
db = QSqlDatabase::addDatabase("QSQLITE","mysql_connection");*/
//設(shè)置數(shù)據(jù)庫路徑,不存在則創(chuàng)建
db.setDatabaseName("sqltest.db");
//db.setUserName("gongjianbo"); //SQLite不需要用戶名和密碼
//db.setPassword("qq654344883");
//打開數(shù)據(jù)庫
if(db.open()){
qDebug()<<"open success";
//關(guān)閉數(shù)據(jù)庫
db.close();
}
}上面的代碼中,先是創(chuàng)建了一個QSqlDatabase對象,該類用于處理數(shù)據(jù)庫的連接。contains方法用于查看給定的連接名稱是否在連接列表中,database方法獲取數(shù)據(jù)庫連接,前提是已使用addDatabase添加數(shù)據(jù)庫連接。addDatabase聲明如下:
QSqlDatabase QSqlDatabase::addDatabase(const QString &type, const QString &connectionName = QLatin1String(defaultConnection)) [static]
第一個參數(shù)對應(yīng)驅(qū)動名,第二個參數(shù)為連接名稱 ,如果不使用默認(rèn)連接名稱“qt_sql_default_connection”的話需要填寫該參數(shù)。
設(shè)置了驅(qū)動及連接名稱后,就是設(shè)置數(shù)據(jù)庫文件的名稱/路徑,因為SQLite不需要用戶名和密碼,接下來直接就可以通過open和close函數(shù)來打開關(guān)閉該數(shù)據(jù)庫了。
此外,如果需要在內(nèi)存中創(chuàng)建數(shù)據(jù)庫,而不是指定一個文件,可以setDatabaseName(“:memory:”);
db.setDatabaseName(":memory:");
3.創(chuàng)建表
SQL語句執(zhí)行需要用到QSqlQuery類,文檔有云:
QSqlQuery封裝了在QSqlDatabase上執(zhí)行的SQL查詢中創(chuàng)建,導(dǎo)航和檢索數(shù)據(jù)所涉及的功能。它可以被用來執(zhí)行DML(數(shù)據(jù)操縱語言)語句,例如select、insert、update、delete,以及DDL(數(shù)據(jù)定義語言)語句,如create table,還可以用于執(zhí)行非標(biāo)準(zhǔn)SQL的特定于數(shù)據(jù)庫的命令。
成功執(zhí)行的SQL語句將查詢的狀態(tài)設(shè)置為活動狀態(tài),以便isActive()返回true。否則,查詢的狀態(tài)將設(shè)置為非活動狀態(tài)。在任何一種情況下,執(zhí)行新的SQL語句時,查詢都位于無效記錄上。必須先將活動查詢導(dǎo)航到有效記錄(以便isActive()返回true),然后才能檢索值。
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
void createTable()
{
//sql語句不熟悉的推薦《sql必知必會》,輕松入門
//如果不存在則創(chuàng)建my_table表
//id自增,name唯一
const QString sql=R"(
CREATE TABLE IF NOT EXISTS my_table (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
name CHAR (50) UNIQUE NOT NULL,
age INTEGER
);)";
//QSqlQuery構(gòu)造前,需要db已打開并連接
//未指定db或者db無效時使用默認(rèn)連接進(jìn)行操作
QSqlQuery query;
if(query.exec(sql)){
qDebug()<<"init table success";
}else{
//打印sql語句錯誤信息
qDebug()<<"init table error"<<query.lastError();
}
}
代碼通過QSqlQuery的exec方法執(zhí)行SQL語句,創(chuàng)建了一個簡單的數(shù)據(jù)表。exec執(zhí)行SQL語句成功返回true,否則返回false。
QSqlQuery的構(gòu)造函數(shù)可以指定QDatabase參數(shù),如果未指定db,或者db無效將使用默認(rèn)連接。
QSqlQuery::QSqlQuery(QSqlDatabase db);
要注意的是,對于SQLite,exec方法一次只能執(zhí)行一個語句。
4.執(zhí)行增刪改查
執(zhí)行了上面的操作且數(shù)據(jù)庫已open,就能使用QSqlQuery的exec方法來完成增刪改查了。
//插入數(shù)據(jù)
void insertRecord(const QString &name, int age)
{
QSqlQuery query;
//方式一,直接執(zhí)行SQL語句
query.exec(QString(R"(INSERT INTO my_table(name,age) VALUES('%1',%2);)")
.arg(name).arg(age));
//方式二,綁定值,待定變量默認(rèn)用問號占位,注意字符串也沒有引號
/*query.prepare(R"(INSERT INTO my_table(name,age) VALUES(?,?);)");
query.addBindValue(name);
query.addBindValue(age);
query.exec();*/
}
//刪除數(shù)據(jù)
void deleteRecord(const QString &name)
{
QSqlQuery query;
//方式一,直接執(zhí)行SQL語句
query.exec(QString(R"(DELETE FROM my_table WHERE name='%1';)")
.arg(name));
//方式二,綁定值,待定變量默認(rèn)用問號占位
/*query.prepare(R"(DELETE FROM my_table WHERE name=?;)");
query.addBindValue(name);
query.exec();*/
}
//更新數(shù)據(jù)
void updateRecord(const QString &name, int age)
{
QSqlQuery query;
//方式一,直接執(zhí)行SQL語句
query.exec(QString(R"(UPDATE my_table SET age=%2 WHERE name='%1';)")
.arg(name).arg(age));
//方式二,綁定值,待定變量默認(rèn)問號,可自定義
/*query.prepare(R"(UPDATE my_table SET age=:age WHERE name=:name;)");
query.bindValue(":name",name);//通過自定義的別名來替代
query.bindValue(":age",age);
query.exec();*/
}
//查詢數(shù)據(jù)
int searchRecord(const QString &name)
{
QSqlQuery query;
query.exec(QString(R"(SELECT age FROM my_table WHERE name='%1';)")
.arg(name));
//獲取查詢結(jié)果的第0個值,
//如果結(jié)果是多行數(shù)據(jù),可用while(query.next()){}遍歷每一行
int ageValue=-1;
if(query.next()){
ageValue=query.value(0).toInt();
}
qDebug()<<ageValue;
return ageValue;
}
可以看到,如果熟悉SQL語句的話,很容易就實現(xiàn)了增刪改查功能。
對于 BLOB 類型,查詢后可以 toByteArray,修改時可以 bindValue QByteArray。
5.進(jìn)階
有時候會遇到大量數(shù)據(jù)操作的情況,這時候用普通的insert之類的語句循環(huán)操作可能會很慢。
技巧一:開啟事務(wù)
SQLite通過執(zhí)行”BEGIN;“或是”BEGIN TRANSACTION;“開啟事務(wù),執(zhí)行”ROLLBACK;“進(jìn)行回滾,執(zhí)行”COMMIT;“或是”END TRANSACTION;“提交事務(wù)。QSqlDatabase也提供了對應(yīng)的transaction、rollback、commit三個函數(shù)來執(zhí)行對應(yīng)操作。
技巧二:關(guān)閉寫同步(synchrnous)
在SQLite中,數(shù)據(jù)庫配置的參數(shù)都由編譯指示(pragma)來實現(xiàn)的,而其中synchronous選項有三種可選狀態(tài),分別是full、normal、off。簡要說來,full寫入速度最慢,但保證數(shù)據(jù)是安全的,不受斷電、系統(tǒng)崩潰等影響,而off可以加速數(shù)據(jù)庫的一些操作,但如果系統(tǒng)崩潰或斷電,則數(shù)據(jù)庫可能會損毀。通過執(zhí)行”PRAGMA synchronous = OFF;“語句,可以提升效率,不過若不是臨時數(shù)據(jù)庫不建議此操作。
SQLite 默認(rèn)是文件鎖, Qt 中 SQLite 默認(rèn)是以多線程讀寫模式打開,如果同時寫入就會出現(xiàn)寫入錯誤:

可以將寫操作上鎖,但是實測線程中循環(huán)寫入時,只讀打開去查詢也是會阻塞很久,毫秒到幾秒不等,這時候就得把超時設(shè)置長一點。

所以還是得讀寫都加鎖,但這也只能解決單個進(jìn)程的并發(fā)訪問。
到此這篇關(guān)于Qt操作SQLite數(shù)據(jù)庫的教程詳解的文章就介紹到這了,更多相關(guān)Qt操作SQLite數(shù)據(jù)庫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- QT連接MYSQL數(shù)據(jù)庫的詳細(xì)步驟
- Qt5連接并操作PostgreSQL數(shù)據(jù)庫的實現(xiàn)示例
- Qt入門學(xué)習(xí)之?dāng)?shù)據(jù)庫操作指南
- QT連接Oracle數(shù)據(jù)庫并實現(xiàn)登錄驗證的操作步驟
- Qt連接MySQL數(shù)據(jù)庫的實現(xiàn)(保姆級成功版教程)
- Qt創(chuàng)建SQlite數(shù)據(jù)庫的示例代碼
- 通過Qt連接OpenGauss數(shù)據(jù)庫的詳細(xì)教程
- QT連接Mysql數(shù)據(jù)庫的實現(xiàn)步驟
- 一篇文章詳解Qt中如何訪問數(shù)據(jù)庫
相關(guān)文章
C語言編程數(shù)據(jù)結(jié)構(gòu)棧與隊列的全面講解示例教程
本文介紹著重介紹數(shù)據(jù)結(jié)構(gòu)-棧和隊列的知識,由于本文也設(shè)計多個動態(tài)內(nèi)存開辟函數(shù),小伙伴們在學(xué)習(xí)本文之前,一定一定一定要把動態(tài)內(nèi)存開辟相關(guān)知識掌握牢固,這樣學(xué)習(xí)起本文才能事半功倍2021-10-10
C++語言數(shù)據(jù)結(jié)構(gòu) 串的基本操作實例代碼
這篇文章主要介紹了C語言數(shù)據(jù)結(jié)構(gòu) 串的基本操作實例代碼的相關(guān)資料,需要的朋友可以參考下2017-04-04
C語言詳細(xì)分析常見字符串函數(shù)與模擬實現(xiàn)
字符串函數(shù)(String?processing?function)也叫字符串處理函數(shù),指的是編程語言中用來進(jìn)行字符串處理的函數(shù),如C,pascal,Visual以及LotusScript中進(jìn)行字符串拷貝,計算長度,字符查找等的函數(shù)2022-03-03
VS2019配置OpenCV時找不到Microsoft.Cpp.x64.user的解決方法
這篇文章主要介紹了VS2019配置OpenCV時找不到Microsoft.Cpp.x64.user的解決方法,需要的朋友可以參考下2020-02-02
C++11中條件標(biāo)量和互斥鎖應(yīng)用出現(xiàn)死鎖問題
這篇文章主要介紹了C++11中條件標(biāo)量和互斥鎖應(yīng)用出現(xiàn)死鎖思考,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-06-06
C語言安全編碼之?dāng)?shù)值中的sizeof操作符
這篇文章主要介紹了C語言安全編碼的數(shù)值中的sizeof操作符用法注意事項,需要的朋友可以參考下2014-07-07

