一.sqlite使用介紹
在Qt中使用SQLite數據庫非常簡單,SQLite是一個輕量級的嵌入式數據庫,不需要單獨的數據庫服務器,完全使用本地文件來存儲數據。
當在Qt中使用SQLite數據庫時,需要涉及到一些SQL語句以及Qt中的相關函數,接下來我將從頭開始介紹所有涉及的語句以及相應的解釋。
1. 連接到數據庫:addDatabase
在Qt中,你可以使用QSqlDatabase來連接數據庫。首先需要添加數據庫類型,然后指定數據庫的名稱:
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("mydatabase.db");
if(!db.open()) {qDebug() << "無法連接到數據庫";return;
}
在這段代碼中,我們首先創建了一個名為mydatabase.db的SQLite數據庫,然后通過open()函數來打開數據庫連接。如果連接失敗,將會輸出錯誤信息。
2. 創建表:CREATE TABLE
一般來說,你需要在數據庫中創建表來存儲數據。這可以通過執行CREATE TABLE語句來實現:
QSqlQuery query;
query.exec("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)");
這里我們使用exec()函數執行SQL語句,創建了一個名為users的表,包含id、name和age三個列。
3. 插入數據:INSERT
當需要在表中插入新的數據時,可以使用SQL的INSERT INTO語句。在Qt中,可以使用QSqlQuery對象的prepare()和bindValue()函數來執行預處理插入語句:
- 常規的數據庫插入語句
INSERT into users(id,name,age)VALUES(111,"name",12)
- Qt中
QString name = "Alice";
int age = 25;
QSqlQuery query;
query.prepare("INSERT INTO users (name, age) VALUES (:name, :age)");
query.bindValue(":name", name);
query.bindValue(":age", age);
if(!query.exec()) {qDebug() << "插入數據失敗:" << query.lastError().text();
}
- prepare和bindValue函數介紹
當在Qt中進行數據庫操作時,使用query.prepare()和query.bindValue()方法可以幫助你執行預處理SQL語句并綁定參數的值。這兩個方法在插入操作中起到了重要作用,下面我將詳細介紹它們的功能和作用:
- query.prepare():
在Qt中,query.prepare()方法用于準備要執行的SQL語句。它的主要作用是將SQL語句中的參數部分用占位符(如:variable)代替,從而形成一個預處理的SQL語句。通過這種方式,可以避免SQL注入攻擊,并提高程序的安全性。
例如,在插入操作中,你可能會使用INSERT INTO table_name (column1, column2, …) VALUES (:value1, :value2, …)這樣的SQL語句,其中的:value1、:value2是占位符,用于將實際的數值動態地填充進去。使用query.prepare()方法可以將這個SQL語句準備好,等待綁定參數值。
- query.bindValue():
一旦調用了query.prepare()方法準備好了SQL語句,接下來就可以使用query.bindValue()方法為每個占位符綁定具體的數值。這個方法的作用是設置預處理語句中的占位符的值,從而將真實的數據插入到SQL語句中。
例如,在前面的插入操作示例中,我們對name和age這兩個占位符使用了query.bindValue()方法,將實際的name和age變量的值綁定到了這兩個占位符上。
使用query.bindValue()方法可以方便地將變量的值插入到SQL語句中,同時還可以防止數據類型轉換錯誤和SQL注入攻擊。
綜上所述,query.prepare()方法用于準備預處理SQL語句,并替換其中的占位符,而query.bindValue()方法則用于將實際的數值綁定到這些占位符上,從而完成對數據庫的插入操作。這兩個方法的結合使用可以簡化代碼編寫,同時提高程序的安全性和可維護性。
4. 查詢數據:SELECT
查詢數據最常見的方式是使用SELECT語句。在Qt中,我們可以通過exec()函數執行SELECT語句,并使用next()函數來逐行獲取結果:
QSqlQuery query;
query.exec("SELECT * FROM users");
while(query.next()) {int id = query.value(0).toInt();QString name = query.value(1).toString();int age = query.value(2).toInt();qDebug() << "ID:" << id << " Name:" << name << " Age:" << age;
}
這段代碼遍歷了users表中的所有行,并輸出每一行的ID、名稱和年齡。
- query.next介紹
在Qt中,query.next()方法用于遍歷查詢結果集中的下一行數據。當執行SELECT查詢語句并通過exec()方法獲取結果集后,可以使用query.next()方法逐行訪問查詢結果中的數據。
每次調用query.next()方法,會將查詢結果集中的指針移到下一行數據。如果存在下一行數據,則該方法返回true,并允許獲取下一行數據;如果不存在下一行數據,則返回false,表示已經遍歷完所有結果。
一般來說,可以在一個循環中使用query.next()方法來遍歷整個查詢結果集,逐行獲取數據并進行相應的處理。在循環中,通常會結合query.value()方法用于獲取特定列的值。
5. 更新數據:UPDATE
在 Qt 中使用 SQLite 實現更新(修改)數據庫操作可以通過執行 SQL UPDATE 語句來實現。下面是一個簡單的示例代碼,演示了如何使用 Qt 和 SQLite 執行更新操作:
#include <QCoreApplication>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);// 連接到SQLite數據庫QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");db.setDatabaseName("database.db"); // 指定SQLite數據庫文件if (!db.open()) {qDebug() << "Error: Unable to connect to database.";return 1;}// 執行 UPDATE 操作QSqlQuery query;query.prepare("UPDATE student SET name = :newName WHERE id = :id");query.bindValue(":newName", "New Name"); // 設置要更新的新名稱query.bindValue(":id", 1); // 設置要更新的記錄的 IDif (query.exec()) {qDebug() << "Update successful";} else {qDebug() << "Update failed:" << query.lastError().text();}return app.exec();
}
6. 刪除數據:DELETE
使用 QSqlQuery 類刪除數據:
QSqlQuery query;
query.prepare("DELETE FROM your_table WHERE condition = :condition"); // 設置刪除語句
query.bindValue(":condition", value); // 綁定條件值
bool success = query.exec(); // 執行刪除操作
if(success) {// 刪除成功
} else {// 刪除失敗,處理錯誤qDebug() << "Error:" << query.lastError().text();
}
7. 更新數據庫中的數據:submitAll
- 這是對模型進行了修改,將數據提交回數據庫中,以保持同步。
// 創建 QSqlTableModel 并設置數據庫表QSqlTableModel model;model.setTable("student");model.select(); // 從數據庫中選擇數據// 創建 QTableView 并設置模型QTableView tableView;tableView.setModel(&model);// 創建一個按鈕,當點擊時提交更新QPushButton updateButton("Update Database");QObject::connect(&updateButton, &QPushButton::clicked, [&model](){if (model.submitAll()) {qDebug() << "Database update successful";} else {qDebug() << "Database update failed:" << model.lastError().text();}});
- model.submitAll介紹
QSqlTableModel 中的 submitAll() 函數是用于將對模型數據的更改提交到數據庫中的方法。當您在 QTableView 中對數據進行了修改、插入或刪除等操作后,調用 submitAll() 函數可將這些更改應用到數據庫中。
submitAll() 函數會執行以下操作:
- 檢查模型中的每一行,如果該行的狀態為 Inserted、Deleted 或 Modified,則將對應的更改提交到數據庫中。
- 如果提交成功,會返回 true;如果提交失敗,會返回 false。您可以通過檢查返回值來確定提交是否成功。
- 如果提交失敗,您可以調用 model.lastError().text() 來獲取詳細的錯誤信息。這將返回一個描述在提交過程中發生的錯誤的字符串。
在模型視圖的結構中,對model是臨時修改數據的中轉站。
8. 更新QSqlQueryModel中的數據
QSqlQueryModel 是一個只讀模型,無法直接編輯數據,因此更新數據的方式不同于可編輯的模型,比如 QSqlTableModel。如果您想要更新 QSqlQueryModel 中的數據,可以重新執行查詢語句或者重新設置查詢。
以下是更新 QSqlQueryModel 中數據的一種常見方法:
- 重新執行查詢語句:您可以重新設置 QSqlQueryModel 的查詢語句,然后調用 setQuery() 方法重新執行查詢。這將重新從數據庫中讀取數據并更新模型中的數據。
QSqlQueryModel model;
model.setQuery("SELECT * FROM your_table");
- 使用 clear() 方法清空數據:如果需要清空 QSqlQueryModel 中的數據,您可以調用 clear() 方法。清空數據后,您可以重新設置查詢或數據源,從而實現更新。
model.clear();
需要注意的是,QSqlQueryModel 是一個只讀模型,不支持直接編輯數據,如果您需要在界面上進行編輯和更新操作,可以考慮使用 QSqlTableModel 或自定義的 QAbstractTableModel。
9. 對指定列進行排序
- 這是對模型進行排序
// 創建 QSqlQueryModel 并設置查詢語句
QSqlQueryModel *queryModel = new QSqlQueryModel;
queryModel->setQuery("SELECT * FROM your_table");// 創建 QSortFilterProxyModel 并設置源模型為 QSqlQueryModel
QSortFilterProxyModel *sortModel = new QSortFilterProxyModel(this);
sortModel->setSourceModel(queryModel);// 設置排序的列索引
int sortColumn = 1; // 假設要按第1列排序
sortModel->sort(sortColumn, Qt::AscendingOrder); // 進行升序排序// 將排序后的模型設置給視圖
yourTableView->setModel(sortModel);
- 對數據庫進行排序
-- 以id列的升序方式進行排序
SELECT id, name, age
FROM your_table
ORDER BY id ASC;SELECT id ,name ,score FROM student ORDER BY id DESC//對模型中的數據進行排序
model->setQuery("SELECT id, name, score FROM student ORDER BY id DESC");
二.成績管理系統實戰
1. 項目效果
- 項目說明:底層存儲數據用的是sqlite,界面展示數據用的是tableView和QSqlQueryModel的視圖模型模式。
2. 項目源碼:
- 類定義
#ifndef STUDENTDLG_H
#define STUDENTDLG_H#include <QDialog>#include <QSqlDatabase> // 專用于連接、創建數據庫
#include <QSqlQuery> // 專用于DML(數據操縱語言)、DDL(數據定義語言)
#include <QSqlQueryModel>//數據庫模型,用來和tableview關聯
#include <QSqlError>
#include <QDebug>
#include <QMessageBox>QT_BEGIN_NAMESPACE
namespace Ui { class StudentDlg; }
QT_END_NAMESPACEclass StudentDlg : public QDialog
{Q_OBJECTpublic:StudentDlg(QWidget *parent = nullptr);~StudentDlg();private slots:void on_pushButtonSort_clicked();void on_pushButton_INSERT_clicked();void on_pushButton_DELETE_clicked();void on_pushButton_UPDATE_clicked();void on_pushButton_SEARCH_clicked();
private: void CreateDatabaseFunc(); // 創建SQLite數據庫void CreateTableFunc(); // 創建SQLite數據表void QueryTableFunc(); // 執行查詢操作QSqlDatabase sqldb; // 創建Qt和數據庫鏈接QSqlQueryModel *model=nullptr;//用來存儲數據
private:Ui::StudentDlg *ui;};
#endif // STUDENTDLG_H
- 類實現
#include "studentdlg.h"
#include "ui_studentdlg.h"
#include<QSortFilterProxyModel>StudentDlg::StudentDlg(QWidget *parent): QDialog(parent), ui(new Ui::StudentDlg)
{ui->setupUi(this);// 調用函數創建且打開數據庫CreateDatabaseFunc();// 調用函數創建數據表CreateTableFunc();
}StudentDlg::~StudentDlg()
{delete ui;
}void StudentDlg::CreateDatabaseFunc() // 創建SQLite數據庫
{// 1:添加數據庫驅動sqldb=QSqlDatabase::addDatabase("QSQLITE");// 2:設置數據庫名稱sqldb.setDatabaseName("studentmis.db");// 3:打開此數據庫是否成功if(sqldb.open()==true){QMessageBox::information(0,"正確","恭喜你,數據庫打開成功!",QMessageBox::Ok);}else{QMessageBox::critical(0,"錯誤","數據庫打開失敗,請重新檢測!",QMessageBox::Ok);}
}void StudentDlg::CreateTableFunc() // 創建SQLite數據表
{QSqlQuery createquery;// 創建SQL語句QString strsql=QString("CREATE TABLE IF NOT EXISTS student(""id int primary key not null,""name text not null,""score real not null)");// 執行SQL語句if(createquery.exec(strsql)==false){QMessageBox::critical(0,"失敗","數據表創建失敗,請重新檢查!",QMessageBox::Ok);}else{QMessageBox::information(0,"成功","恭喜你,數據表創建成功!",QMessageBox::Ok);}// 準備數據模型model = new QSqlQueryModel();model->setQuery("SELECT id, name, score FROM student"); // 執行查詢// 將數據模型與QTableView綁定//QTableView *tableView = new QTableView();ui-> tableView->setModel(model);ui->tableView->resizeColumnsToContents(); // 調整列寬度使數據能夠完全顯示// 顯示QTableViewui->tableView->show();}
void StudentDlg::QueryTableFunc() // 執行查詢操作
{QSqlQuery query;query.exec("SELECT * FROM users");while(query.next()) {int id = query.value(0).toInt();QString name = query.value(1).toString();double score = query.value(2).toDouble();qDebug() << "ID:" << id << " Name:" << name << " Score:" << score;}}void StudentDlg::on_pushButtonSort_clicked()
{// QSortFilterProxyModel *sortModel = new QSortFilterProxyModel(this);
// sortModel->setSourceModel(model);// // 設置排序的列索引
// int sortColumn = 1; // 假設要按第1列排序
// sortModel->sort(sortColumn, Qt::DescendingOrder); // 進行升序排序// // 將排序后的模型設置給視圖
// ui->tableView->setModel(sortModel);// //使用sql語句進行操作
// QSqlQuery query;
// query.exec("SELECT id ,name ,score FROM student ORDER BY id DESC");//更新數據庫中的數據model->setQuery("SELECT id, name, score FROM student ORDER BY id DESC");//model->setQuery("SELECT * FROM student");ui->tableView->viewport()->update();
}void StudentDlg::on_pushButton_INSERT_clicked()
{QSqlQuery sqlquery;int id=ui->lineEdit_ID->text().toInt();if(id==0){QMessageBox::critical(this,"失敗","提示:輸入錯誤?學號不能為0?",QMessageBox::Ok);return ;}QString name=ui->lineEdit_NAME->text();if(name==""){QMessageBox::critical(this,"失敗","提示:輸入錯誤?姓名不能為空?",QMessageBox::Ok);return ;}double score=ui->lineEdit_SCORE->text().toDouble();if(score<0 || score>100){QMessageBox::critical(this,"失敗","提示:輸入錯誤?分數范圍(0-100)?",QMessageBox::Ok);return ;}QString strs=QString("insert into student ""values(%1,'%2',%3)").arg(id).arg(name).arg(score);if(sqlquery.exec(strs)==false){QMessageBox::critical(0,"失敗","向數據表插入記錄失敗,請重新檢查!",QMessageBox::Ok);}else{QMessageBox::information(0,"成功","恭喜你,向數據表插入記錄成功!",QMessageBox::Ok);}}void StudentDlg::on_pushButton_DELETE_clicked()
{int id = ui->lineEdit_ID->text().toInt();QSqlQuery query;query.prepare("DELETE FROM student WHERE id = :id"); // 設置刪除語句query.bindValue(":id", id); // 綁定條件值bool success = query.exec(); // 執行刪除操作if(success) {// 刪除成功} else {// 刪除失敗,處理錯誤qDebug() << "Error:" << query.lastError().text();}//更新數據庫中的數據model->setQuery("SELECT * FROM student");ui->tableView->viewport()->update();
}void StudentDlg::on_pushButton_UPDATE_clicked()
{// 執行 UPDATE 操作QString New_Name=ui->lineEdit_NAME->text();int id=ui->lineEdit_ID->text().toUInt();QSqlQuery query;query.prepare("UPDATE student SET name = :newName WHERE id = :id");query.bindValue(":newName", New_Name); // 設置要更新的新名稱query.bindValue(":id", id); // 設置要更新的記錄的 IDif (query.exec()) {qDebug() << "Update successful";} else {qDebug() << "Update failed:" << query.lastError().text();}}void StudentDlg::on_pushButton_SEARCH_clicked()
{QSqlQuery query;query.exec("SELECT * FROM student");while(query.next()) {int id = query.value(0).toInt();QString name = query.value(1).toString();double score = query.value(2).toDouble();qDebug() << "ID:" << id << " Name:" << name << " Score:" << score;}//更新數據庫中的數據model->setQuery("SELECT * FROM student");ui->tableView->viewport()->update();
}