Qt入門(mén)學(xué)習(xí)之?dāng)?shù)據(jù)庫(kù)操作指南
一、數(shù)據(jù)庫(kù)
Qt中的Qt SQL模塊提供了對(duì)數(shù)據(jù)庫(kù)的支持,模塊中類(lèi)可分為三層:驅(qū)動(dòng)層,sql接口層,用戶(hù)層。
- 驅(qū)動(dòng)層:(QSqlDriver,QSqlDriverCreator,QSqlDriverCreatorBase,QSqlDriverPlugin)為具體的數(shù)據(jù)庫(kù)和SQL接口層之間提供了底層的橋梁;
- SQL接口層:(QSqlDatabase,QSqlQuery,QSqlError,QSqlRecord)提供了對(duì)數(shù)據(jù)庫(kù)的訪(fǎng)問(wèn),其中QSqlDatabase類(lèi)用來(lái)創(chuàng)建連接,QSqlQuery類(lèi)可以使用SQL語(yǔ)句來(lái)實(shí)現(xiàn)與數(shù)據(jù)庫(kù)交互;
- 用戶(hù)接口層:(QSqlTableModel,QSqlQueryModel,QSqlRelationalTableModel)實(shí)現(xiàn)了將數(shù)據(jù)庫(kù)中的數(shù)據(jù)鏈接到窗口部件上,這些類(lèi)是使用模型/視圖框架實(shí)現(xiàn)的,它們是更高層次的抽象;
1.數(shù)據(jù)庫(kù)驅(qū)動(dòng)
Qt SQL模塊使用數(shù)據(jù)庫(kù)驅(qū)動(dòng)插件來(lái)和不同的數(shù)據(jù)庫(kù)接口進(jìn)行通信。由于Qt SQL模塊的接口是獨(dú)立于數(shù)據(jù)庫(kù)的,所以所有數(shù)據(jù)庫(kù)特定的代碼都包含在了這些驅(qū)動(dòng)中。Qt默認(rèn)支持一些驅(qū)動(dòng):
| 驅(qū)動(dòng)名稱(chēng) | 數(shù)據(jù)庫(kù) |
|---|---|
| QSQLITE2 | SQLite2版本 |
| QSQLITE | SQLite3版本 |
| QMYSQL | MySQL |
| QODBC | SQL Service |
| QPSQL | PostgreSQL(>=7.3版本) |
2.查詢(xún)驅(qū)動(dòng)
#include <QApplication>
#include <QSqlDatabase>
#include <QDebug>
#include <QStringList>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QStringList drivers = QSqlDatabase::drivers();
foreach(QString driver, drivers)
qDebug() << driver;
return a.exec();
}
在.pro文件中加入sql模塊

3.連接數(shù)據(jù)庫(kù)
數(shù)據(jù)庫(kù)連接使用連接名來(lái)定義,而不是使用數(shù)據(jù)庫(kù)名,可以向相同的數(shù)據(jù)庫(kù)創(chuàng)建多個(gè)連接。QSqlDatabase也支持默認(rèn)連接的概念,默認(rèn)連接就是一個(gè)沒(méi)有命名的連接。在使用QSqlQuery或者QSqlQueryModel的成員函數(shù)時(shí)需要指定一個(gè)連接名作為參數(shù),如果沒(méi)有指定,那么就會(huì)使用默認(rèn)連接。
原型:QSqlDatabase QSqlDatabase::addDatabase(const QString &type, const
QString &connectionName = QLatin1String( defaultConnection ))
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("127.0.0.1");
db.setDatabaseName("book");
db.setUserName("root");
db.setPassword("123456");
if(!db.open())
{
qDebug() << "fail to connect mysql" << db.lastError().text();
}
創(chuàng)建兩個(gè)名為“first”和“second”的連接:
QSqlDatabase firstDB = QSqlDatabase::addDatabase("QMYSQL", "first");
QSqlDatabase secondDB = QSqlDatabase::addDatabase("QMYSQL", "second");
創(chuàng)建完連接后,可以在任何地方使用QSqlDatabase::database()靜態(tài)函數(shù)通過(guò)連接名稱(chēng)獲取指向數(shù)據(jù)庫(kù)連接的指針,如果調(diào)用該函數(shù)時(shí)沒(méi)有指明連接名稱(chēng),那么會(huì)返回默認(rèn)連接,例如:
QSqlDatabase defaultDB = QSqlDatabase::database();
QSqlDatabase firstDB = QSqlDatabase::database("first");
QSqlDatabase secondDB = QSqlDatabase::database("second");
要移除一個(gè)數(shù)據(jù)庫(kù)連接,需要先使用QSqlDatabase::close()關(guān)閉數(shù)據(jù)庫(kù),然后使用靜態(tài)函數(shù)QSqlDatabase::removeDatabase()移除該連接。
連接SQL Server數(shù)據(jù)庫(kù)
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
db.setDatabaseName(QString("DRIVER={SQL SERVER}SERVER=%1;DATABASE=%2;UID=%3;PWD=%4;")
.arg("IP").arg("dbname").arg("user").arg("password"));
bool ok =db.open();
連接SQLite數(shù)據(jù)庫(kù)
QSqlDatabase db1 = QSqlDatabase::addDatabase("QSQLITE");
db1.setHostName("IP");
db1.setDatabaseName("dbname");
db1.setUserName("user");
db1.setPassword("password");
4.執(zhí)行sql語(yǔ)句
QSqlQuery類(lèi)提供了一個(gè)接口,用于執(zhí)行SQL語(yǔ)句和瀏覽查詢(xún)的結(jié)果集。要執(zhí)行一個(gè)SQL語(yǔ)句,只需要簡(jiǎn)單的創(chuàng)建一個(gè)QSqlQuery對(duì)象,然后調(diào)用QSqlQuery::exec()函數(shù)即可。
QSqlQuery query;
query.exec("select * from student");
QSqlQuery提供了對(duì)結(jié)果集的訪(fǎng)問(wèn),可以一次訪(fǎng)問(wèn)一條記錄。當(dāng)執(zhí)行完exec()函數(shù)后,QSqlQuery的內(nèi)部指針會(huì)位于第一條記錄前面的位置。必須調(diào)用一次QSqlQuery::next()函數(shù)來(lái)使其前進(jìn)到第一條記錄,然后可以重復(fù)使用next()函數(shù)來(lái)訪(fǎng)問(wèn)其他的記錄,直到該函數(shù)的返回值為false,
while(query.next())
{
qDebug() << query.value(0).toInt() << query.value(1).toString();
}
在QSqlQuery類(lèi)中提供了多個(gè)函數(shù)來(lái)實(shí)現(xiàn)在結(jié)果集中進(jìn)行定位,比如next()定位到下一條記錄,previous()定位到前一條記錄,first()定位的第一條記錄,last()定位到最后一條記錄,seek(n)定位到第n條記錄。當(dāng)前行的索引可以使用at()返回;record()函數(shù)可以返回當(dāng)前指向的記錄。
5.插入數(shù)據(jù)
插入一條記錄
query.exec("insert into student (id, name) values (1, 'LI')");
同一時(shí)間插入多條記錄,可以使用占位符來(lái)完成。Qt支持兩種占位符:名稱(chēng)綁定和位置綁定。
1名稱(chēng)綁定
query.prepare("insert into student (id, name) values (:id, :name)");
int idValue = 1;
QString nameValue = "Li";
query.bindValue(":id", idValue);
query.bindValue(":name", nameValue);
query.exec();
2位置綁定
query.prepare("insert into student (id, name) values (?, ?)");
int idValue = 1;
QString nameValue = "Li";
query.addBindValue(idValue);
query.addBindValue(nameValue);
query.exec();
當(dāng)要插入多條記錄時(shí),只需要調(diào)用QSqlQuery::prepare()一次,然后使用多次bindValue()或者addBindValue()函數(shù)來(lái)綁定需要的數(shù)據(jù),最后調(diào)用一次exec()函數(shù)就可以了。其實(shí),進(jìn)行多條數(shù)據(jù)插入時(shí),還可以使用批處理進(jìn)行:
query.prepare("insert into student (id, name) values (?, ?)");
QVariantList ids;
ids << 1 << 2 << 3;
query.addBindValue(ids);
QVariantList names;
names << "Li" << "Wang" << "Liu";
query.addBindValue(names);
if(!query.execBatch())
qDebug() << query.lastError();
6.事務(wù)
事務(wù)可以保證一個(gè)復(fù)雜的操作的原子性,就是對(duì)于一個(gè)數(shù)據(jù)庫(kù)操作序列,這些操作要么全部做完,要么一條也不做,是不可分割的工作單位。如果底層的數(shù)據(jù)庫(kù)引擎支持事務(wù),QSqlDriver::hasFeature(QSqlDriver::Transactions)會(huì)返回true??梢允褂肣SqlDatabase::transaction()來(lái)啟動(dòng)一個(gè)事務(wù),然后編寫(xiě)希望在事務(wù)中執(zhí)行的SQL語(yǔ)句,最后調(diào)用QSqlDatabase::commit()提交或者QSqlDatabase::rollback()回滾。使用事務(wù)必須在創(chuàng)建查詢(xún)以前就開(kāi)始事務(wù)
QSqlDatabase::database().transaction();
QSqlQuery query;
query.exec("SELECT id FROM student WHERE name = 'Li'");
if (query.next())
{
int id = query.value(0).toInt();
query.exec("INSERT INTO project (id, name, ownerid) "
"VALUES (201, 'MProject', "
+ QString::number(id) + ')');
}
QSqlDatabase::database().commit();
二 ,sql模型類(lèi)
Qt還提供了3個(gè)更高層的類(lèi)來(lái)訪(fǎng)問(wèn)數(shù)據(jù)庫(kù),分別是QSqlQueryModel、QSqlTableModel和QSqlRelationalTableModel。
這3個(gè)類(lèi)都是從QAbstractTableModel派生來(lái)的,可以很容易地實(shí)現(xiàn)將數(shù)據(jù)庫(kù)中的數(shù)據(jù)在QListView和QTableView等項(xiàng)視圖類(lèi)中進(jìn)行顯示。使用這些類(lèi)的另一個(gè)好處是,這樣可以使編寫(xiě)的代碼很容易的適應(yīng)其他的數(shù)據(jù)源。例如,如果開(kāi)始使用了QSqlTableModel,而后來(lái)要改為使用XML文件來(lái)存儲(chǔ)數(shù)據(jù),這樣需要做的僅是更換一個(gè)數(shù)據(jù)模型
1.QSqlQueryModel模型
QSqlQueryModel提供了一個(gè)基于SQL查詢(xún)的只讀模型。
QSqlQueryModel *model = new QSqlQueryModel(this);
model->setQuery("select * from student");
model->setHeaderData(0, Qt::Horizontal, tr("學(xué)號(hào)"));
model->setHeaderData(1, Qt::Horizontal, tr("姓名"));
model->setHeaderData(2, Qt::Horizontal, tr("課程"));
ui->tableView->setModel(model);
ui->tableView->verticalHeader()->setHidden(true);
ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);

先創(chuàng)建了QSqlQueryModel對(duì)象,然后使用setQuery()來(lái)執(zhí)行SQL語(yǔ)句查詢(xún)整張student表,并使用setHeaderData()來(lái)設(shè)置顯示的標(biāo)頭。后面創(chuàng)建了視圖,并將QSqlQueryModel對(duì)象作為其要顯示的模型。這里要注意,其實(shí)QSqlQueryModel中存儲(chǔ)的是執(zhí)行完setQuery()函數(shù)后的結(jié)果集,所以視圖中顯示的是結(jié)果集的內(nèi)容。QSqlQueryModel中還提供了columnCount()返回一條記錄中字段的個(gè)數(shù);rowCount()返回結(jié)果集中記錄的條數(shù);record()返回第n條記錄;index()返回指定記錄的指定字段的索引;clear()可以清空模型中的結(jié)果集。
2.QSqlTableModel模型
QSqlTableModel提供了一個(gè)一次只能操作一個(gè)SQL表的讀寫(xiě)模型,它是QSqlQuery的更高層次的替代品,可以瀏覽和修改獨(dú)立的SQL表,并且只需編寫(xiě)很少的代碼,而且不需要了解SQL語(yǔ)法。
創(chuàng)建數(shù)據(jù)表
QSqlQuery query;
// 創(chuàng)建student表
query.exec("create table student (id int primary key, "
"name varchar, course int)");
query.exec("insert into student values(1, '李', 10)");
query.exec("insert into student values(2, '馬', 11)");
query.exec("insert into student values(3, '孫', 12)");
// 創(chuàng)建course表
query.exec("create table course (id int primary key, "
"name varchar, teacher varchar)");
query.exec("insert into course values(10, '數(shù)學(xué)', '王老師')");
query.exec("insert into course values(11, '英語(yǔ)', '張老師')");
query.exec("insert into course values(12, '計(jì)算機(jī)', '李老師')");
顯示表:
QSqlTableModel *model = new QSqlTableModel(this);
model->setTable("student");
model->select();
// 設(shè)置編輯策略
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
ui->tableView->setModel(model);
ui->tableView->verticalHeader()->setHidden(true);
ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);

創(chuàng)建一個(gè)QSqlTableModel后,只需使用setTable()來(lái)為其指定數(shù)據(jù)庫(kù)表,然后使用select()函數(shù)進(jìn)行查詢(xún),調(diào)用這兩個(gè)函數(shù)就等價(jià)于執(zhí)行了“select * from student”語(yǔ)句。這里還可以使用setFilter()來(lái)指定查詢(xún)時(shí)的條件。在使用該模型以前,一般還要設(shè)置其編輯策略,它由QSqlTableModel::EditStrategy枚舉類(lèi)型定義。
| 常量 | 描述 |
|---|---|
| QSqlTableModel::OnFieldChange | 所有對(duì)模型的改變都會(huì)立即應(yīng)用到數(shù)據(jù)庫(kù) |
| QSqlTableModel::OnRowChange | 對(duì)一條記錄的改變會(huì)在用戶(hù)選擇另一條記錄時(shí)被應(yīng)用 |
| QSqlTableModel::OnManualSubmit | 所有的改變都會(huì)在模型中進(jìn)行緩存,直到調(diào)用submitAll()或者reverAll()函數(shù) |
修改
// 開(kāi)始事務(wù)操作
model->database().transaction();
if (model->submitAll())
{
if(model->database().commit()) // 提交
QMessageBox::information(this, tr("tableModel"),tr("數(shù)據(jù)修改成功!"));
} else
{
model->database().rollback(); // 回滾
QMessageBox::warning(this, tr("tableModel"),tr("數(shù)據(jù)庫(kù)錯(cuò)誤: %1").arg(model->lastError().text()),QMessageBox::Ok);
}
撤銷(xiāo)修
model->revertAll();
查詢(xún)
//全部數(shù)據(jù)
model->setTable("student");
model->select();
//進(jìn)行篩選
QString name = "xxx" ;
// 根據(jù)姓名進(jìn)行篩選,一定要使用單引號(hào)
model->setFilter(QString("name = '%1'").arg(name));
model->select();
升序
//id字段,即第0列,升序排列 model->setSort(0, Qt::AscendingOrder); model->select();
刪除
// 獲取選中的行
int curRow = ui->tableView->currentIndex().row();
// 刪除該行
model->removeRow(curRow);
int ok1 = QMessageBox::warning(this,tr("刪除當(dāng)前行!"),
tr("你確定刪除當(dāng)前行嗎?"), QMessageBox::Yes, QMessageBox::No);
if(ok == QMessageBox::No)
{ // 如果不刪除,則撤銷(xiāo)
model->revertAll();
} else { // 否則提交,在數(shù)據(jù)庫(kù)中刪除該行
model->submitAll();
}
3.QSqlRelationalTableModel模型
QSqlRelationalTableModel繼承自QSqlTableModel,并且對(duì)其進(jìn)行了擴(kuò)展,提供了對(duì)外鍵的支持。一個(gè)外鍵就是一個(gè)表中的一個(gè)字段和其他表中的主鍵字段之間的一對(duì)一的映射。例如,student表中的course字段對(duì)應(yīng)的是course表中的id字段,那么就稱(chēng)字段course是一個(gè)外鍵。因?yàn)檫@里的course字段的值是一些數(shù)字,這樣的顯示很不友好,使用關(guān)系表格模型,就可以將它顯示為course表中的name字段的值。
QSqlRelationalTableModel *model = new QSqlRelationalTableModel(this);
model->setTable("student");
model->setRelation(2, QSqlRelation("course", "id", "name"));
model->select();
ui->tableView->setModel(model);
ui->tableView->verticalHeader()->setHidden(true);
ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);

Qt中還提供了一個(gè)QSqlRelationalDelegate委托類(lèi),它可以為QSqlRelationalTableModel顯示和編輯數(shù)據(jù)。這個(gè)委托為一個(gè)外鍵提供了一個(gè)QComboBox部件來(lái)顯示所有可選的數(shù)據(jù),這樣就顯得更加清晰了。
view->setItemDelegate(new QSqlRelationalDelegate(view));

總結(jié)
到此這篇關(guān)于Qt入門(mén)學(xué)習(xí)之?dāng)?shù)據(jù)庫(kù)操作指南的文章就介紹到這了,更多相關(guān)Qt數(shù)據(jù)庫(kù)操作內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- QT連接MYSQL數(shù)據(jù)庫(kù)的詳細(xì)步驟
- Qt5連接并操作PostgreSQL數(shù)據(jù)庫(kù)的實(shí)現(xiàn)示例
- QT連接Oracle數(shù)據(jù)庫(kù)并實(shí)現(xiàn)登錄驗(yàn)證的操作步驟
- Qt連接MySQL數(shù)據(jù)庫(kù)的實(shí)現(xiàn)(保姆級(jí)成功版教程)
- Qt創(chuàng)建SQlite數(shù)據(jù)庫(kù)的示例代碼
- 通過(guò)Qt連接OpenGauss數(shù)據(jù)庫(kù)的詳細(xì)教程
- QT連接Mysql數(shù)據(jù)庫(kù)的實(shí)現(xiàn)步驟
- Qt操作SQLite數(shù)據(jù)庫(kù)的教程詳解
- 一篇文章詳解Qt中如何訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)
相關(guān)文章
C語(yǔ)言自定義數(shù)據(jù)類(lèi)型的結(jié)構(gòu)體、枚舉和聯(lián)合詳解
這篇文章主要給大家介紹了關(guān)于C語(yǔ)言自定義數(shù)據(jù)類(lèi)型的結(jié)構(gòu)體、枚舉和聯(lián)合的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05
C++?boost?thread庫(kù)用法詳細(xì)講解
Boost是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱(chēng)。Boost庫(kù)是一個(gè)可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開(kāi)發(fā)引擎之一,是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱(chēng)2022-11-11
C語(yǔ)言中字符串庫(kù)函數(shù)的實(shí)現(xiàn)及模擬
C語(yǔ)言中有很多數(shù)據(jù)類(lèi)型,比如int(整數(shù)類(lèi)型)、char(字符類(lèi)型)、以及浮點(diǎn)型的double(雙精度)等。但是有一點(diǎn)就是我們發(fā)現(xiàn)這里并沒(méi)有提到我們常見(jiàn)的有關(guān)字符串的類(lèi)型。本文為大家介紹了C語(yǔ)言中字符串庫(kù)函數(shù)的實(shí)現(xiàn)及模擬,需要的可以參考一下2022-11-11

