天天看點

QT學習第七天

一、資料庫操作

      Qt 提供了 QtSql 子產品來提供平台獨立的基于 SQL 的資料庫操作。這裡我們所說的“平台獨立”,既包括作業系統平台,有包括各個資料庫平台。另外,我們強調了“基于 SQL”,因為 NoSQL 資料庫至今沒有一個通用查詢方法,是以不可能提供一種通用的 NoSQL 資料庫的操作。Qt 的資料庫操作還可以很友善的與 model/view 架構進行整合。通常來說,我們對資料庫的操作更多地在于對資料庫表的操作,而這正是 model/view 架構的長項。

Qt 使用QSqlDatabase表示一個資料庫連接配接。更底層上,Qt 使用驅動(drivers)來與不同的資料庫 API 進行互動。Qt 桌面版本提供了如下幾種驅動:

驅動 資料庫
QDB2 IBM DB2 (7.1 或更新版本)
QIBASE Borland InterBase
QMYSQL MySQL
QOCI Oracle Call Interface Driver
QODBC Open Database Connectivity (ODBC) – Microsoft SQL Server 及其它相容 ODBC 的資料庫
QPSQL PostgreSQL (7.3 或更新版本)
QSQLITE2 SQLite 2
QSQLITE SQLite 3
QSYMSQL 針對 Symbian 平台的SQLite 3
QTDS Sybase Adaptive Server (自 Qt 4.7 起廢除)

不過,由于受到協定的限制,Qt 開源版本并沒有提供上面所有驅動的二進制版本,而僅僅以源代碼的形式提供。通常,Qt 隻預設搭載 QSqlite 驅動(這個驅動實際還包括 Sqlite 資料庫,也就是說,如果需要使用 Sqlite 的話,隻需要該驅動即可)。我們可以選擇把這些驅動作為 Qt 的一部分進行編譯,也可以當作插件編譯。

如果習慣于使用 SQL 語句,我們可以選擇QSqlQuery類;如果隻需要使用高層次的資料庫接口(不關心 SQL 文法),我們可以選擇使用QsqlTableModel類。

在使用時,我們可以通過

QSqlDatabase::drivers();      

找到系統中所有可用的資料庫驅動的名字清單。我們隻能使用出現在清單中的驅動。由于預設情況下,QtSql 是作為 Qt 的一個子產品提供的。為了使用有關資料庫的類,我們必須早 .pro 檔案中增加這麼一句:

QT += sql      

這表示,我們的程式需要使用 Qt 的 core、gui 以及 sql 三個子產品。注意,如果需要同時使用 Qt4 和 Qt5 編譯程式,通常我們的 .pro 檔案是這樣的:

QT += core gui sql
greaterThan(QT_MAJOR_VERSION,4): QT += widgets      

這兩句也很明确:Qt 需要加載 core、gui 和 sql 三個子產品,如果主機闆本> 4,則再加 widgets 子產品。

bool connect(const QString &dbName)
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
//    db.setHostName("host");
//    db.setDatabaseName("dbname");
//    db.setUserName("username");
//    db.setPassword("password");
    db.setDatabaseName(dbName);
    if (!db.open()) {
        QMessageBox::critical(0, QObject::tr("Database Error"),
                              db.lastError().text());
        return false;
    }
    return true;
}      

我們使用connect()函數建立一個資料庫連接配接。我們使用QSqlDatabase::addDatabase()靜态函數完成這一請求,也就是建立了一個QSqlDatabase執行個體。注意,資料庫連接配接使用自己的名字進行區分,而不是資料庫的名字。例如,我們可以使用下面的語句:

QSqlDatabase db=QSqlDatabase::addDatabase("QSQLITE",
                            QString("con%1").arg(dbName));      

此時,我們是使用addDatabase()函數的第二個參數來給這個資料庫連接配接一個名字。在這個例子中,用于區分這個資料庫連接配接的名字是QString("conn%1").arg(dbName),而不是 “QSQLITE”。這個參數是可選的,如果不指定,系統會給出一個預設的名字QSqlDatabase::defaultConnection,此時,Qt 會建立一個預設的連接配接。如果你給出的名字與已存在的名字相同,新的連接配接會替換掉已有的連接配接。通過這種設計,我們可以為一個資料庫建立多個連接配接。

我們這裡使用的是 sqlite 資料庫,隻需要指定資料庫名字即可。如果是資料庫伺服器,比如 MySQL,我們還需要指定主機名、端口号、使用者名和密碼,這些語句使用注釋進行了簡單的說明。接下來我們調用了QSqlDatabase類的open()函數,打開這個資料庫連接配接。通過檢查open()函數的傳回值,我們可以判斷資料庫是不是正确打開。

QtSql 子產品中的類大多具有lastError()函數,用于檢查最新出現的錯誤。如果你發現資料庫操作有任何問題,應該使用這個函數進行錯誤的檢查。這一點我們也在上面的代碼中進行了展現。當然,這隻是最簡單的實作,一般來說,更好的設計是,不要在資料庫操作中混雜界面代碼(并且将這個connect()函數放在一個專門的資料庫操作類中)。

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    if (connect("demo.db")) {
        QSqlQuery query;
        if (!query.exec("CREATE TABLE student ("
                        "id INT PRIMARY KEY AUTOINCREMENT,"
                        "name VARCHAR(255),"
                        "age INT)")) 
{
       QMessageBox::critical(0, 
QObject::tr("Database Error"), 
query.lastError().text());
            return 1;
        }
    } else {
        return 1;
    }
    return a.exec();
}      
if (connect("demo.db")) {
    QSqlQuery query;
    query.prepare("INSERT INTO student (name, age) VALUES (?, ?)");
    QVariantList names;
    names << "Tom" << "Jack" << "Jane" << "Jerry";
    query.addBindValue(names);
    QVariantList ages;
    ages << 20 << 23 << 22 << 25;
    query.addBindValue(ages);
    if (!query.execBatch()) {
        QMessageBox::critical(0, QObject::tr("Database Error"),
                              query.lastError().text());
    }
 
    query.exec("SELECT name, age FROM student");
    while (query.next()) {
        QString name = query.value(0).toString();
        int age = query.value(1).toInt();
        qDebug() << name << ": " << age;
    }
} else {
    return 1;
}      

二、使用模型操作資料庫

一處我們使用 SQL 語句完成了對資料庫的正常操作,包括簡單的 CREATE、SELECT 等語句的使用。我們也提到過,Qt 不僅提供了這種使用 SQL 語句的方式,還提供了一種基于模型的更進階的處理方式。這種基于QSqlTableModel 的模型處理更為進階,如果對

SQL 語句不熟悉,并且不需要很多複雜的查詢,這種QSqlTableModel模型基本可以滿足一般的需求。本節我們将介紹QSqlTableModel的一般使用,對比 SQL 語句完成對資料庫的增删改查等的操作。值得注意的是,QSqlTableModel并不一定非得結合 QListView或QTableView使用,我們完全可以用其作一般性處理。

查詢操作

if (connect("demo.db")) {
    QSqlTableModel model;
    model.setTable("student");
    model.setFilter("age > 20 and age < 25");
    if (model.select()) {
        for (int i = 0; i < model.rowCount(); ++i) {
            QSqlRecord record = model.record(i);
            QString name = record.value("name").toString();
            int age = record.value("age").toInt();
            qDebug() << name << ": " << age;
        }
    }
} else {
    return 1;
}      

插入操作

QSqlTableModel model;
model.setTable("student");
int row = 0;
model.insertRows(row, 1);
model.setData(model.index(row, 1), "Cheng");
model.setData(model.index(row, 2), 24);
model.submitAll();      

更新操作

QSqlTableModel model;
model.setTable("student");
model.setFilter("age = 25");
if (model.select()) {
    if (model.rowCount() == 1) {
        QSqlRecord record = model.record(0);
        record.setValue("age", 26);
        model.setRecord(0, record);
        model.submitAll();
    }
}      

删除操作

QSqlTableModel model;
model.setTable("student");
model.setFilter("age = 25");
if (model.select()) {
    if (model.rowCount() == 1) {
        model.removeRows(0, 1);
        model.submitAll();
    }
}