1. 程式人生 > >Qt連線並操作SQL資料庫(Qt學習①)

Qt連線並操作SQL資料庫(Qt學習①)

初學者記錄學習內容,如有錯誤請各位前輩指點。

DOS命令操作資料庫

雖然在window下是可以用DOS命令建立並操作資料庫,但是當涉及到一些比較複雜的資料操作的時候還是比較繁瑣,這裡做個簡單的示例,這裡對mySQL的Qt配置不做多言,貧道使用的Qt5.8已經自帶配置檔案了。
用DOS命令建立資料庫,輸入密碼後,顯示當前存在的資料庫輸入命令show databases;(命令後面一定要加“;”)
這裡寫圖片描述
create database student;建立一個名叫student的資料庫;
這裡寫圖片描述
use student; 對資料庫進行操作;
這裡寫圖片描述
呃,黑色好難看,換個背景色,然後在資料庫中建立表格,並查看錶格詳情。
這裡寫圖片描述


在資料庫中插入資料。
這裡寫圖片描述
更多命令可自行查詢,其實這些並沒有什麼卵用,不易於資料的修改,推薦使用SQL資料庫視覺化工具,貧道使用的是“Navicat for MySQL”。
我們在Navicat中建立表格information,使用者密碼設定為777777,然後就可以將Qt專案與資料庫建立連線了。

Qt與SQL資料庫

注意要在專案中加入資料庫的應用,要先在.pro中加入sql,儲存。

QT       += core gui sql

連線mySQL資料庫

在建構函式中加入這段程式碼;

  QSqlDatabase dataBase=QSqlDatabase::addDatabase("QMYSQL"
); dataBase.setHostName("localhost"); dataBase.setUserName("root"); dataBase.setPassword("777777"); dataBase.setDatabaseName("picturedata"); dataBase.open();

第一句是我們所加入的資料庫的驅動型別,使用mySQL寫入”QMYSQL”,如果是使用sqlite資料庫寫入”QSQLITE”,使用Oracle資料庫寫入”QOICQ” 。如上的QSqlDatabase dataBase是定義了一個數據庫的控制代碼,又addDatabase返回並載入mySQL的驅動。資料庫支援遠端連線,setHostName()設定資料庫主機名,這裡是本地資料庫。然後是setUserName()設定資料庫使用者名稱,setPassword()設定密碼,setDatabaseName()設定資料庫名。 這些一定要一致。
如果沒有問題,連線成功以後open會返回一個bool型的變數true,我們可以接收一下這個變數qDebug顯示成功或輸出錯誤資訊。

bool ok=dataBase.open();
    if(ok)
    {
      qDebug()<<"open database success";
    }
    else
    {
      qDebug()<<"error open database because"<<this->dataBase.lastError().text();
    }

qDebug在專案編譯初期可以這樣做,但是如果不開啟編譯器是無法看到顯示的資訊的,即是說使用者是無法用這種方法來判斷是否連線成功的,所以可以改成用QMessageBox彈出小對話方塊來判斷是否能夠連線成功,後面會說到。

連線成功使用者需要完成功能對資料庫的增刪改查,先看設計的介面如圖:
這裡寫圖片描述
上面的lineEdit填入資料,兩個pushButton,savedataBase將資料寫入資料庫,resetdataBase將資料庫中的資料清除,並清空介面,也就是說這個工程的資料庫中始終只有一條資料。同時注意,介面開啟時,lineEdit會顯示資料庫中存在的表資訊到介面上。

插入資料

我們執行工程開啟介面,在lineEdit中寫入資料,點選儲存,資料插入到資料庫中,插入語句
注意插入語句的語法:
INSERT INTO table_name (列1, 列2,…) VALUES (值1, 值2,….);
如下的這種方式是我認為最簡單的資料庫操作函式,相當於直接在Qt中書寫SQL語句。

       QSqlQuery query(dataBase);
       QString datestr = ui->dateEdit->dateTime().toString("dd-MM-yyyy");
       QString timestr = ui->dateEdit->time().toString("hh:mm:ss");
    QString sql=QString("select *from information");
    query.exec(sql);
    if(query.numRowsAffected() == 0)
    {
    QString savesql = QString("INSERT INTO information(userName,IP,storagePath,productName,date)");
    savesql += QString(" VALUES('%1','%2','%3','%4','%5')").arg(ui->userNameEdit->text())
            .arg(ui->ipAddressEdit->text())
            .arg(ui->storagePathEdit->text())
            .arg(ui->productNameEdit->text())
            .arg(datestr+' '+timestr);
    bool ok=query.exec(savesql);
    if(ok){
          QMessageBox::about(NULL, "Save", "save new database success");
          }
      else{
           QMessageBox::about(NULL, "Save", "error save new database");
          }
    }

在QString中寫插入語句insert,當然第一行程式碼也可以寫成這樣子

QString("INSERT INTO information(userName,IP,storagePath,productName,date)
VALUES('%1','%2','%3','%4','%5')");

但是由於程式碼過長不便於檢視最好進行拆分。在需要呼叫lineEdit中的輸入語句時,把值寫成引數”%1”””%2”……等,在後面加入.arg().arg()……;括號內可以寫從控制元件獲取文字資訊的函式,或直接寫入已經賦值的變數名,或者值本身。

Qt提供的一種格式化字串輸出的函式arg():
1. str=QString(“%1 %2 (%3s-%4s)”)
2. arg(“permissive”).arg(“society”).arg(1950).arg(1970);
這段程式碼中,%1, %2, %3, %4作為佔位符,將被後面的arg()函式中的內容依次替換,比如%1將被替換成permissive,%2將被替換成society,%3將被替換成1950,%4將被替換曾1970,最後,這句程式碼輸出為:permissive society (1950s-1970s). arg()函式比起sprintf()來是型別安全的,同時它也接受多種的資料型別作為引數,都會被轉化為QString型別然後進行替換。

使用bool ok=query.exec(savesql)執行該sql語句,返回一個bool型的結果。如上面說到的,可用一個變數來接收這個結果,由結果的不同true或fulse返回不同的QMessageBox小對話來讓使用者得到是否執行成功。
前面的一些程式碼在最後一部分會有說到。

修改資料

在資料庫中已經有資料的情況下,可以實現修改介面文字,點選儲存,實現資料庫中的值的修改,修改語句

QString updatesql = QString("UPDATE information SET userName='%1',IP='%2',storagePath='%3',productName='%4',date='%5' WHERE IP=%6")
                      .arg(ui->userNameEdit->text())
                      .arg(ui->ipAddressEdit->text())
                      .arg(ui->storagePathEdit->text())
                      .arg(ui->productNameEdit->text())
                      .arg(datestr+' '+timestr)
                      .arg(oldIP);
    bool ok=query.exec(updatesql);
    if(ok){
        QMessageBox::about(NULL, "Save", "save database success");}
      else{
        QMessageBox::about(NULL, "Save", "error save database");}

注意updata語句的語法是:
UPDATE 表名稱 SET 列名稱 = 新值 WHERE 列名稱 = 某值
where之後需要給出修改的條件,如題要獲取未修改的資料庫中的ip的值。
貧僧之前將修改的條件設定為介面上獲取的IP:

QString updatesql = QString("UPDATE information SET userName='%1',IP='%2',storagePath='%3',productName='%4',date='%5' WHERE IP=%6")
           .arg(ui->userNameEdit->text())
           .arg(ui->ipAddressEdit->text())
           .arg(ui->storagePathEdit->text())
           .arg(ui->productNameEdit->text())
           .arg(datestr+' '+timestr).arg(ui->ipAddressEdit->text());

此時%6所接收到的IP是你準備要修改成的,而此時資料庫中並沒有的值,導致sql語句執行之後資料庫中毫無變化,修改失敗。可以在執行修改之前,定義一個變數oldIP去儲存資料庫中原來的IP值,寫到主函式中。作為update語句的條件傳入。

QString oldIP;
oldIP=ui->ipAddressEdit->text();

刪除資料

接著實現點選重新整理按鈕,刪除資料庫中的使用者資訊,刪除語句
注意delete的語法是DELETE FROM 表名稱 WHERE 列名稱 = 值;
IP條件引用與上例相同。

    QSqlQuery deletequery(dataBase);
    QString deletesql = QString("DELETE FROM information WHERE IP='%1'").arg(oldIP);
    bool ok=deletequery.exec(deletesql);
    if(ok)
    {
      QMessageBox::about(NULL, "Reset", "Reset database success");
      ui->userNameEdit->clear();
      ui->ipAddressEdit->clear();
      ui->storagePathEdit->clear();
      ui->productNameEdit->clear();
      ui->dateEdit->clear();
    }
    else
    {
       QMessageBox::about(NULL, "Reset", "error reset database");
    }

刪除資料後,需要清空lineEdit()上的資料,呼叫.clear();

其他的幾個重點問題

判斷資料庫是否為空

我們再回頭看插入語句的程式碼會發現一個問題,這裡有一個問題,只有一個儲存save按鈕,當資料庫是否為空,兩種情況點選button是執行update或insert這兩種哪一種sql語句呢?這裡就需要加入一個判斷資料庫是否為空。使用select語句查詢語句查詢表,query.exec()執行語句。

QString sql=QString("select *from information");
query.exec(sql);

然後呼叫query.numRowsAffected()

int QSqlQuery::numRowsAffected () const
返回有多少行記錄被結果集的 SQL語句影響了,如果不能確定將返回 -1 。注意,對於 SELECT語句,此值等同於size()如果查詢處於非活動狀態(isActive()返回FALSE),將反回 -1。

如果資料庫為空,將有0行語句被影響,那麼就執行插入語句,否則執行修改語句。

QdateTimeEdit的處理

注意介面中獲取時間和日期的控制元件,使用的是QdateTimeEdit,從這個控制元件獲得的資料插入到資料庫中時總是出現問題,此處的是從中.dateTime()和.time()單獨獲取日期和時間,以dd-MM-yyyy和hh:mm:ss的形式toString();單獨儲存,同時傳入。

QString datestr = ui->dateEdit->dateTime().toString("dd-MM-yyyy");
QString timestr = ui->dateEdit->time().toString("hh:mm:ss");

寫入資料庫時進行組合arg(datestr+’ ‘+timestr)

資料庫顯示到介面

如果資料庫中有已插入的資料,專案執行起來時,資料會從資料庫載入到lineEdit上顯示到介面中,這裡自然又要用到select查詢語句,涉及到對執行SQL語句後返回的結果集的操作,結果集其實就是查詢到的所有記錄的集合,需要注意這個集合中的記錄是從0開始編號的,這裡使用value(int n)來獲取屬性的值,其中n表示你查詢的第n個屬性。比如value(0),返回userName的值,轉化為String型別.settext()顯示到lineEdit中。
關注:MySql執行之後返回的結果集指標都指向陣列第一條語句之前,因此需要呼叫一個next(),更便於使用while迴圈顯示,而且每執行一次該函式,便指向相鄰的下一條記錄。Sqllite資料庫也是如此,要先呼叫next()。

QSqlQuery showquery(dataBase);
    QString showsql=QString("select *from information");
    showquery.exec(showsql);
    if(showquery.numRowsAffected() != 0)
    {
        showquery.next();  
        ui->userNameEdit->setText(showquery.value(0).toString());
        ui->ipAddressEdit->setText(showquery.value(1).toString());
        ui->storagePathEdit->setText(showquery.value(2).toString());
        ui->productNameEdit->setText(showquery.value(3).toString());
        ui->dateEdit->setDateTime(QDateTime::fromString(showquery.value(4).toString(),"dd-MM-yyyy hh:mm:ss"));
    }

我們注意到,資料庫中始終保持了一行程式碼需要顯示,但是如果資料庫中是3×5的表,select*以後返回的結果集是個二維陣列,若需要用上述的方式的顯示到3×5的lineEdit中的話,可以使用while迴圈呼叫query.value();

while(query.next()){
            ui->button1->setText(query.value(0).toString());
            ui->button2->setText(query.value(1).toString());
            ui->button3->setText(query.value(2).toString());
            ui->button4->setText(query.value(3).toString());
            ui->button5->setText(query.value(4).toString());
        }

While語句開始執行,第一次執行query.next()後指向第一行資料,然後五次呼叫.value(),遍歷五列資料(value只管列),逐次顯示到介面上。

結束,如有錯誤,還望指正。