閱讀346 返回首頁    go 技術社區[雲棲]


[Qt教程] 第23篇 數據庫(三)利用QSqlQuery類執行SQL語句

[Qt教程] 第23篇 數據庫(三)利用QSqlQuery類執行SQL語句

樓主
 發表於 2013-5-15 22:39:29 | 查看: 813| 回複: 0
利用QSqlQuery類執行SQL語句

版權聲明

該文章原創於作者yafeilinux,轉載請注明出處!




導語

       SQL即結構化查詢語言,是關係數據庫的標準語言。前麵兩節中已經在Qt裏利用QSqlQuery類執行了SQL語句,這一節我們將詳細講解該類的使用。需要說明,因為我們重在講解Qt中的數據庫使用,而非專業的講解數據庫知識,所以不會對數據庫中的一些知識進行深入講解。



環境:Windows Xp + Qt 4.8.4+Qt Creator2.6.2




目錄

一、創建數據庫連接
二、操作結果集
三、在SQL語句中使用變量
四、批處理操作
五、事務操作




正文


一、創建數據庫連接
       前麵我們是在主函數中創建數據庫連接,然後打開並使用。實際中為了明了方便,一般將數據庫連接單獨放在一個頭文件中。下麵來看一個例子。

1.新建Qt Gui應用,項目名稱為myquery,基類為QMainWindow,類名為MainWindow。完成後打開myquery.pro並將第一行代碼更改為:

QT       += coregui sql

       然後保存該文件。

2.向項目中添加新的C++頭文件,名稱為connection.h,然後打開該文件,更改如下:
#ifndef CONNECTION_H
#define CONNECTION_H
#include <QMessageBox>
#include <QSqlDatabase>
#include <QSqlQuery>
static bool createConnection()
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(":memory:");
    if (!db.open()) {
       QMessageBox::critical(0, qApp->tr("Cannot open database"),
           qApp->tr("Unable to establisha database connection."
                     ), QMessageBox::Cancel);
       return false;
    }
    QSqlQuery query;
    query.exec("create table student (id int primary key, "
               "name varchar(20))");
    query.exec("insert into student values(0, 'first')");
    query.exec("insert into student values(1, 'second')");
    query.exec("insert into student values(2, 'third')");
    query.exec("insert into student values(3, 'fourth')");
    query.exec("insert into student values(4, 'fifth')");
    return true;
}
#endif // CONNECTION_H


       在這個頭文件中我們添加了一個建立連接的函數,使用這個頭文件的目的就是要簡化主函數中的內容。這裏先創建了一個SQLite數據庫的默認連接,設置數據庫名稱時使用了“:memory:”,表明這個是建立在內存中的數據庫,也就是說該數據庫隻在程序運行期間有效,等程序運行結束時就會將其銷毀。當然,大家也可以將其改為一個具體的數據庫名稱,比如“my.db”,這樣就會在項目目錄中創建該數據庫文件了。下麵使用open()函數將數據庫打開,如果打開失敗,則彈出提示對話框。最後使用QSqlQuery創建了一個student表,並插入了包含idname兩個屬性的五條記錄,如下圖所示。其中,id屬性是int類型的,“primary key”表明該屬性是主鍵,它不能為空,而且不能有重複的值;而name屬性是varchar類型的,並且不大於20個字符。這裏使用的SQL語句都要包含在雙引號中,如果一行寫不完,那麼分行後,每一行都要使用兩個雙引號引起來。
23-1.jpg
       需要注意,代碼中的query沒有進行任何指定就可以操作前麵打開的數據庫,這是因為現在隻有一個數據庫連接,它就是默認連接,這時候所有的操作都是針對該連接的。但是如果要同時操作多個數據庫連接,就需要進行指定了,這方麵內容可以參考《Qt Creator快速入門》的第17章。


3.下麵我們到main.cpp中調用連接函數。
#include "mainwindow.h"
#include <QApplication>
#include "connection.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
   
    if (!createConnection())
           return 1;
   
    MainWindow w;
    w.show();
   
    return a.exec();
}


4.我們往界麵上添加一個按鈕來實現查詢操作。雙擊mainwindow.ui文件進入設計模式。然後將一個Push Button拖到界麵上,並修改其顯示文本為“查詢”。效果如下圖所示。
23-2.jpg


5.在查詢按鈕上點擊鼠標右鍵,選擇“轉到槽”,然後選擇clicked()單擊信號槽並點擊確定,如下圖所示。
23-3.jpg


6.將槽的內容更改如下:
void MainWindow::on_pushButton_clicked()
{
    QSqlQuery query;
    query.exec("select * from student");
    while(query.next())
    {
       qDebug() << query.value(0).toInt()
                                      << query.value(1).toString();
    }
}

7.mainwindow.cpp文件中添加頭文件:
#include <QSqlQuery>
#include <QDebug>


8.運行程序,然後按下查詢按鈕,在應用程序輸出窗口將會輸出結果,效果如下圖所示。
23-4.jpg



二、操作結果集

在前麵的程序中,我們使用query.exec("select * from student");查詢出表中所有的內容。其中的SQL語句“select * from student”中“*”號表明查詢表中記錄的所有屬性。而當query.exec("select * from student");這條語句執行完後,我們便獲得了相應的執行結果,因為獲得的結果可能不止一條記錄,所以稱之為結果集。
結果集其實就是查詢到的所有記錄的集合,在QSqlQuery類中提供了多個函數來操作這個集合,需要注意這個集合中的記錄是從0開始編號的。最常用的操作有:
  • seek(int n) query指向結果集的第n條記錄;
  • first() query指向結果集的第一條記錄;
  • last() query指向結果集的最後一條記錄;
  • next() query指向下一條記錄,每執行一次該函數,便指向相鄰的下一條記錄;
  • previous() query指向上一條記錄,每執行一次該函數,便指向相鄰的上一條記錄;
  • record() :獲得現在指向的記錄;
  • value(int n) :獲得屬性的值。其中n表示你查詢的第n個屬性,比方上麵我們使用“select * from student”就相當於“select id, name from student”,那麼value(0)返回id屬性的值,value(1)返回name屬性的值。該函數返回QVariant類型的數據,關於該類型與其他類型的對應關係,可以在幫助中查看QVariant
  • at() :獲得現在query指向的記錄在結果集中的編號。
       需要特別注意,剛執行完query.exec("select *from student");這行代碼時,query是指向結果集以外的,我們可以利用query.next()使得 query指向結果集的第一條記錄。當然我們也可以利用seek(0)函數或者first()函數使query指向結果集的第一條記錄。但是為了節省內存開銷,推薦的方法是,在query.exec("select * from student");這行代碼前加上query.setForwardOnly(true);這條代碼,此後隻能使用next()seek()函數。
       下麵我們通過例子來演示一下這些函數的使用。將槽更改如下:
void MainWindow::on_pushButton_clicked()
{
    QSqlQuery query;
    query.exec("select * from student");
    qDebug() << "exec next() :";
    //開始就先執行一次next()函數,那麼query指向結果集的第一條記錄
    if(query.next())
    {
       //獲取query所指向的記錄在結果集中的編號
       int rowNum = query.at();
       //獲取每條記錄中屬性(即列)的個數
       int columnNum = query.record().count();
       //獲取"name"屬性所在列的編號,列從左向右編號,最左邊的編號為0
       int fieldNo = query.record().indexOf("name");
       //獲取id屬性的值,並轉換為int型
       int id = query.value(0).toInt();
       //獲取name屬性的值
       QString name = query.value(fieldNo).toString();
       //將結果輸出
       qDebug() << "rowNum is : " << rowNum
                 << " id is : " << id
                 << " name is : " << name
                 << " columnNum is : " << columnNum;
    }
//定位到結果集中編號為2的記錄,即第三條記錄,因為第一條記錄的編號為0
    qDebug() << "exec seek(2) :";
    if(query.seek(2))
    {
       qDebug() << "rowNum is : " << query.at()
                 << " id is : " << query.value(0).toInt()
                 << " name is : " << query.value(1).toString();
    }
    //定位到結果集中最後一條記錄
    qDebug() << "exec last() :";
    if(query.last())
    {
       qDebug() << "rowNum is : " << query.at()
                 << " id is : " << query.value(0).toInt()
                 << " name is : " << query.value(1).toString();
    }
}

       最後在mainwindow.cpp中添加#include <QSqlRecord>頭文件包含,運行程序,點擊查詢按鈕,輸出結果如下圖所示。
23-5.jpg


三、在SQL語句中使用變量


1.我們先來看一個例子。首先在設計模式往界麵上添加一個Spin Box部件,如下圖所示。
23-6.jpg


2.將查詢按鈕槽裏麵的內容更改如下:
void MainWindow::on_pushButton_clicked()
{
    QSqlQuery query;
    int id = ui->spinBox->value();
    query.exec(QString("select name from student where id =%1")
               .arg(id));
    query.next();
    QString name = query.value(0).toString();
    qDebug() << name;
}
       這裏使用了QString類的arg()函數實現了在SQL語句中使用變量,我們運行程序,更改Spin Box的值,然後點擊查詢按鈕,效果如下圖所示。
23-7.jpg

3.其實在QSqlQuery類中提供了數據綁定同樣可以實現在SQL語句中使用變量,雖然它也是通過占位符來實現的,不過使用它形式上更明了一些。下麵先來看一個例子,將查詢按鈕槽更改如下:
  1. void MainWindow::on_pushButton_clicked()
  2. {
  3.     QSqlQuery query;
  4.     query.prepare("insert into student (id, name) "
  5.                   "values (:id, :name)");
  6.     query.bindValue(0, 5);
  7.     query.bindValue(1, "sixth");
  8.     query.exec();
  9.     query.exec("select * from student");
  10.     query.last();
  11.     int id = query.value(0).toInt();
  12.     QString name = query.value(1).toString();
  13.     qDebug() << id << name;
  14. }
複製代碼
       這裏在student表的最後又添加了一條記錄。然後我們先使用了prepare()函數,在其中利用了“:id”“:name”來代替具體的數據,而後又利用bindValue()函數給idname兩個屬性賦值,這稱為綁定操作。其中編號01分別代表“:id”“:name”,就是說按照prepare()函數中出現的屬性從左到右編號,最左邊是
特別注意,在最後一定要執行exec()函數,所做的操作才能被真正執行。運行程序,點擊查詢按鈕,可以看到前麵添加的記錄的信息。這裏的“:id”和“:name”,叫做占位符,這是ODBC數據庫的表示方法,還有一種Oracle的表示方法就是全部用“?”號。例如:
query.prepare("insert into student(id, name) "
                  "values (?, ?)");
query.bindValue(0, 5);
query.bindValue(1, "sixth");
query.exec();


也可以利用addBindValue()函數,這樣就可以省去編號,它是按順序給屬性賦值的,如下:


query.prepare("insert into student(id, name) "
                  "values (?, ?)");
query.addBindValue(5);
query.addBindValue("sixth");
query.exec();


當用ODBC的表示方法時,我們也可以將編號用實際的占位符代替,如下:


query.prepare("insert into student(id, name) "
                      "values (:id, :name)");
query.bindValue(":id", 5);
query.bindValue(":name", "sixth");
query.exec();
以上各種形式的表示方式效果是一樣的。


4.下麵我們演示一下通過綁定操作在SQL語句中使用變量。更改槽函數如下:
void MainWindow::on_pushButton_clicked()
{
    QSqlQuery query;
    query.prepare("select name from student where id = ?");
    int id = ui->spinBox->value();
    query.addBindValue(id);
    query.exec();
    query.next();
    qDebug() << query.value(0).toString();
}
       運行程序,可以實現通過Spin Box的值來進行查詢。



四、批處理操作

       當要進行多條記錄的操作時,我們就可以利用綁定進行批處理。將槽更改如下:
void MainWindow::on_pushButton_clicked()
{
    QSqlQuery q;
    q.prepare("insert into student values (?, ?)");
    QVariantList ints;
    ints << 10 << 11 << 12 << 13;
    q.addBindValue(ints);
    QVariantList names;
    // 最後一個是空字符串,應與前麵的格式相同
        names << "xiaoming" << "xiaoliang"
                      << "xiaogang" << QVariant(QVariant::String);
    q.addBindValue(names);
    if (!q.execBatch()) //進行批處理,如果出錯就輸出錯誤
       qDebug() << q.lastError();
    //下麵輸出整張表
    QSqlQuery query;
    query.exec("select * from student");
    while(query.next())
    {
       int id = query.value(0).toInt();
       QString name = query.value(1).toString();
       qDebug() << id << name;
    }
}
       然後需要在mainwindow.cpp上添加頭文件包含:#include <QSqlError>我們在程序中利用列表存儲了同一屬性的多個值,然後進行了值綁定。最後執行execBatch()函數進行批處理。注意程序中利用QVariant(QVariant::String)來輸入空值NULL,因為前麵都是QString類型的,所以這裏要使用QVariant::String 使格式一致化。
運行程序,效果如下圖所示:
27-8.jpg



五、事務操作

       事務可以保證一個複雜的操作的原子性,就是對於一個數據庫操作序列,這些操作要麼全部做完,要麼一條也不做,它是一個不可分割的工作單位。在Qt中,如果底層的數據庫引擎支持事務,那麼QSqlDriver::hasFeature(QSqlDriver::Transactions)會返回true。可以使用QSqlDatabase::transaction()來啟動一個事務,然後編寫一些希望在事務中執行的SQL語句,最後調用QSqlDatabase::commit()或者QSqlDatabase::rollback()。當使用事務時必須在創建查詢以前就開始事務,例如:
QSqlDatabase::database().transaction();
QSqlQuery query;
query.exec("SELECT id FROMemployee WHERE name = 'Torild Halvorsen'");
if (query.next()) {
    int employeeId = query.value(0).toInt();
    query.exec("INSERT INTO project(id, name, ownerid) "
               "VALUES (201, 'ManhattanProject', "
               + QString::number(employeeId) + ')');
}
QSqlDatabase::database().commit();



結語

       對執行SQL語句我們就介紹這麼多,其實Qt中提供了更為簡單的不需要SQL語句就可以操作數據庫的方法,我們在下一節講述這些內容。




涉及到的源碼:  myquery01.zip (3.2 KB, 下載次數: 7)  myquery02.zip (3.23 KB, 下載次數: 5) 



最後更新:2017-04-03 14:54:11

  上一篇:go PHP 日期 加減 月數,天數,周數,小時,分,秒等等
  下一篇:go [Qt教程] 第22篇 數據庫(二)編譯MySQL數據庫驅動