QSqlQuery類提供了一個用於執行SQL語句和瀏覽查詢的結果集的接口。數據庫
QSqlQueryModel和QSqlTableModel類提供了一個用於訪問數據庫的高級接口,這將在下一節介紹。若是你不熟悉SQL,你能夠直接使用下一節介紹的高級接口類。app
1 執行一個查詢函數
要執行一個SQL語句,簡單的建立一個QSqlQuery對象,而後調用QSqlQuery::exec()方法便可,以下所示:性能
QSqlQuery query; query.exec("SELECT name, salary FROM employee WHERE salary > 50000");
QSqlQuery的構造函數接受一個可選的QSqlDatabase對象參數,用來指定將使用哪個數據庫鏈接。在上面的例子中,咱們並無指定任何鏈接,所以使用默認鏈接。若是執行查詢時出錯,exec()將返回false,錯誤緣由能夠經過QSqlQuery::lastError()查看。優化
2 瀏覽查詢結果ui
QSqlQuery提供了一個訪問一條查詢結果記錄的方法。在調用了exec()方法以後,QSqlQuery的內部指針定位到了第一條記錄以前的位置。咱們必須調用一次QSqlQuery::next()內部指針就移動到第一條記錄上,而後重複調用next()方法就能夠移動到其餘記錄上,直到該函數返回false爲止。下面給出一個典型的循環依次遍歷全部的記錄:this
while (query.next()) { QString name = query.value(0).toString(); int salary = query.value(1).toInt(); qDebug() << name << salary; }
QSqlQuery::value()函數返回當前記錄的一個字段值。字段的索引號從0開始計數。QSqlQuery::value()返回一個QVariant,這個類型能夠保存各類C++和核心的Qt數據類型,好比int, QString和QByteArray等。不一樣的數據庫類型將自動地映射到最近的Qt等價類型。在上面的代碼中,咱們使用了QVariant::toString()和QVariant::toInt()將變量類型轉換爲了QString和int。spa
補充:關於value()方法的參數-索引號的取值範圍問題,咱們只知道第一個字段對應的索引號爲0,可是並不知道最後一個字段的索引號的時候,咱們能夠遍歷全部可能值,因爲當value()函數的索引號非法時,會返回一個非法的QVariant變量,所以,咱們能夠經過判斷返回的QVariant變量的合法性來得知是否已經到了最後一個字段。下面給出一段示例代碼:指針
while (query.next()){ int i = 0; QString result; QVariant temp; while ((temp = query.value(i++)).isValid()){ result += temp.toString(); result += " | "; } ui->textBrowser->append(result); }
下面給出一個MYSQL與Qt支持的數據類型之間的轉換關係表:code
SQLITE3與Qt支持的數據類型之間的轉換關係表以下:
你可使用QSqlQuery::next(),QSqlQuery::previous(), QSqlQuery::first()和QSqlQuery::last()來先後移動指向記錄位置的指針。可使用QSqlQuery::at()返回當前行的索引號,若是對應的數據庫支持,可使用QSqlQuery::size()返回查詢結果集的總的行數(MYSQL是支持的)。
要驗證一個數據庫驅動是否支持某一個特性,QSqlDriver::hasFeature()。下面的示例咱們調用調用QSqlQuery::size()來檢查底層的數據庫是否支持此特性,不然,咱們只能瀏覽到最後一條記錄,利用查詢的位置來獲得查詢結果中一共有多少條記錄。
QSqlQuery query; int numRows; query.exec("SELECT name, salary FROM employee WHERE salary > 50000"); QSqlDatabase defaultDB = QSqlDatabase::database(); if (defaultDB.driver()->hasFeature(QSqlDriver::QuerySize)) { numRows = query.size(); } else { // this can be very slow query.last(); numRows = query.at() + 1; }
若是你在遍歷查詢結果集的時候只使用正值參數的next()和seek(),你能夠在調用exec()以前調用QSqlQuery::setForwartOnly(true)。當你在操做大量結果集的時候,這是一個簡單的優化單能夠明顯加速你的查詢。
3 插入、更新和刪除記錄
QSqlQuery能夠執行任意的SQL語句。下面的示例展現了使用INSERT語句向表中插入一條記錄:
QSqlQuery query; query.exec("INSERT INTO employee (id, name, salary) " "VALUES (1001, 'Thad Beaumont', 65000)");
若是你想要同時插入許多條記錄,一個有效的方法就是將查詢語句和真實的值分離,這個可使用佔位符來實現。Qt支持兩種佔位符:名稱綁定和位置綁定。下面是一個名稱綁定的示例:
QSqlQuery query; query.prepare("INSERT INTO employee (id, name, salary) " "VALUES (:id, :name, :salary)"); query.bindValue(":id", 1001); query.bindValue(":name", "Thad Beaumont"); query.bindValue(":salary", 65000); query.exec();
下面的代碼時位置綁定的示例:
QSqlQuery query; query.prepare("INSERT INTO employee (id, name, salary) " "VALUES (?, ?, ?)"); query.addBindValue(1001); query.addBindValue("Thad Beaumont"); query.addBindValue(65000); query.exec();
這兩種語句對於Qt提供的全部數據庫驅動都支持。當須要插入多條記錄時,只須要調用 一次QSqlQuery::prepare(),而後使用屢次bindValue()或者addBindValue()來綁定須要的數據,最後再調用一次exec()函數就能夠了。
拋開性能,使用佔位符的一個好處就是你能夠指定任意的值而不用擔憂缺乏特殊字符。
更新一條記錄與插入操做很是類似:
QSqlQuery query; query.exec("UPDATE employee SET salary = 70000 WHERE id = 1003");
你也可使用名稱或位置綁定來關聯實際的參數值。
最後,下面給出一條刪除語句:
QSqlQuery query; query.exec("DELETE FROM employee WHERE id = 1007");
4 事務
若是底層的數據庫引擎支持事務,那麼QSqlDriver::hasFeature(QSqlDriver::Transactions)會返回true。可使用QSqlDatabase::transaction()啓動一個事務,而後編寫一些但願在事務中執行的SQL語句,最後調用QSqlDatabase::commit()或者QSqlDatabase::rollback()。當使用事務時必須在建立查詢之前就開始事務,例如:
QSqlDatabase::database().transaction(); QSqlQuery query; query.exec("SELECT id FROM employee WHERE name = 'Torild Halvorsen'"); if (query.next()) { int employeeId = query.value(0).toInt(); query.exec("INSERT INTO project (id, name, ownerid) " "VALUES (201, 'Manhattan Project', " + QString::number(employeeId) + ')'); } QSqlDatabase::database().commit();
事務能夠保證一個複雜操做的原子性,就是對於一個數據庫操做序列,這些操做要麼所有作完,要麼一條也不作,它是一個不可分割的工做單位。