在上一節中,我們直接調用QSqlQuery:exec()對數據庫進行增刪改查等簡單操作。
在項目開發中,爲了實現系統的低耦合,我們就必須封裝出一個數據庫功能模塊。
一、prepare()
首先創建一個頭文件"attend_db.h"。
初始化數據庫操作,包括創建數據庫文件、建表、以及添加一些基礎數據。最好還要返回數據庫操作的一些信息(最重要的是錯誤信息)。
QSqlError db_Init()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:"); //使用內存數據庫
if(!db.open())
{
//打開失敗
return db.lastError();
}
QSqlQuery query;
//創建組別表,人員表,考勤記錄表
if(!query.exec("CREATE TABLE table_group(group_id INTEGER PRIMARY KEY, group_name VARCHAR)"))
{
return query.lastError();
}
if(!query.exec("CREATE TABLE table_user(user_id VARCHAR PRIMARY KEY, group_id INTEGER)"))
{
return query.lastError();
}
if(!query.exec("CREATE TABLE table_record(user_id VARCHAR, datetime VARCHAR)"))
{
return query.lastError();
}
//添加組別數據
if(!query.prepare("INSERT INTO table_group(group_id, group_name) VALUES(:gourp_id, :group_name)"))
{
return query.lastError();
}
db_AddGroup(query, 1, "student");
db_AddGroup(query, 2, "teacher");
//添加人員數據
if(!query.prepare("INSERT INTO table_user(user_id, group_id) VALUES(:user_id, :group_id)"))
{
return query.lastError();
}
db_AddUser(query, "T0001", 2);
qdb_AddUser(query, "T0002", 2);
db_AddUser(query, "S111201", 1);
//添加考勤記錄數據
if(!query.prepare("INSERT INTO table_record(user_id, datetime) VALUES(:user_id, :datetime)"))
{
return query.lastError();
}
db_AddRecord(query, "T0001", QDateTime::currentDateTime());
db_AddRecord(query, "T0002", QDateTime::currentDateTime());
db_AddRecord(query, "S111201", QDateTime::currentDateTime());
return QSqlError();
}
這裏對錶的添加數據不再簡單的使用QSqlQuery:exec()直接執行語句了。爲了模塊化,我們還要封裝出對錶數據的操作函數(包括增刪改查)。
提供對外的接口供上層應用使用。形參最好就僅僅是表的參量,這樣清晰明瞭。
Qt提供了bool prepare(const QString& query)接口。(SQLite也提供了該API函數)
query.prepare("INSERT INTO table_group(group_id, group_name) VALUES(:gourp_id, :group_name)")
我們先使用了prepare()函數,在其中利用了“:group_id”和“:group_name”來代替具體的數據,之後就可以利用bindValue()函數給group_id和group_name兩個屬性賦值,這稱爲綁定操作。
例:
query.bindValue(0, 1);
query.bindValue(1, 'student');
其中編號0和1分別代表“:group_id”和“:group_name”,就是說按照prepare()函數中出現的屬性從左到右編號,最左邊是0 。這裏的“:group_id”和“:group_name”,叫做佔位符,這是ODBC數據庫的表示方法,還有一種Oracle的表示方法就是全部用“?”號。
query.prepare("INSERT INTO table_group(group_id, group_name) VALUES(?, ?)")
這是對單條記錄的綁定,當然綁定完還是要調用exec()的,否則語句不會被執行。
當用ODBC的表示方法時,我們也可以將編號用實際的佔位符代替。這裏就不具體介紹了。
我們也可以進行批量處理
void addBindValue(const QVariant& val, QSql::ParamType type = QSql::In);
通過調用addBindValue()增加值val值列表。 QVariantList GroupIDs;
GroupIDs << 1 << 2;
QVariantList GroupNames;
GroupNames << "student" << "teacher";
query.addBindValue(GroupIDs);
query.addBindValue(GroupNames);
query.execBatch();
查看下ececBatch()的文檔。
/*
Executes a previously prepared SQL query in a batch. All the bound parameters have to be lists of variants. If the database doesn't support batch executions, the driver will simulate it using conventional exec()
calls.
*/
如果數據庫不支持批量處理,則用exec()來代替。
二、執行SQL語句後返回的結果集
/*下文不是原創、存屬轉載*/
結果集其實就是查詢到的所有記錄的集合,而在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()函數。
基友們。~~神棍節快樂。
在這裏附上程序源代碼下載鏈接:qt_深入QSqlQuery