閱讀1004 返回首頁    go 阿裏雲 go 技術社區[雲棲]


iOS數據持久化-SQLite數據庫使用詳解

使用SQLite數據庫

創建數據庫

創建數據庫過程需要3個步驟:

1、使用sqlite3_open函數打開數據庫;

2、使用sqlite3_exec函數執行Create Table語句,創建數據庫表;

3、使用sqlite3_close函數釋放資源。

這個過程中使用了3個SQLite3函數,它們都是純C語言函數,通過Objective-C去調用C函數當然不是什麼問題,但是也要注意Objective-C數據類型與C數據類型兼容性問題。

下麵我們使用SQLite技術實現備忘錄案例,與屬性列表文件實現一樣,我們隻需要修改持久層工程(PersistenceLayer)中NoteDAO類就可以了。首先我們需要添加SQLite3庫到工程環境中,有3個工程需要添加到哪個呢?應該添加到可以運行的工程即表示層工程PresentationLayer。選擇工程PresentationLayer中TARGETS→PresentationLayer→Link Binary With Libraries,點擊左下角的“+”,彈出對話框選擇libsqlite3.dylib或libsqlite3.0.dylib,在彈出的對話框中點擊Add添加。

1

NoteDAO.h文件的修改:

#import ”Note.h”

#import ”sqlite3.h”

 

#define DBFILE_NAME @”NotesList.sqlite3″

 

@interface NoteDAO : NSObject

{

sqlite3 *db;

}

 

+ (NoteDAO*)sharedManager;

 

- (NSString *)applicationDocumentsDirectoryFile;

- (void)createEditableCopyOfDatabaseIfNeeded;

 

//插入Note方法

-(int) create:(Note*)model;

 

//刪除Note方法

-(int) remove:(Note*)model;

 

//修改Note方法

-(int) modify:(Note*)model;

 

//查詢所有數據方法

-(NSMutableArray*) findAll;

 

//按照主鍵查詢數據方法

-(Note*) findById:(Note*)model;

 

@end


我們需要使用語句#import ”sqlite3.h”引入sqlite3頭文件,而且需要定義sqlite3*成員變量db。NoteDAO.m中的createEditableCopyOfDatabaseIfNeeded方法:

- (void)createEditableCopyOfDatabaseIfNeeded {

 

NSString *writableDBPath = [self applicationDocumentsDirectoryFile];

if (sqlite3_open([writableDBPath UTF8String], &db) != SQLITE_OK) { ①

sqlite3_close(db);  ②

NSAssert(NO,@”數據庫打開失敗。”);

} else {

char *err;

NSString *createSQL = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS Note

(cdate TEXT PRIMARY KEY, content TEXT);"]; ③

if (sqlite3_exec(db,[createSQL UTF8String],NULL,NULL,&err) != SQLITE_OK) { ④

sqlite3_close(db); ⑤

NSAssert1(NO, @”建表失敗, %s”, err);  ⑥

}

sqlite3_close(db);  ⑦

}

}


createEditableCopyOfDatabaseIfNeeded方法用於創建數據庫,第1步打開數據庫,代碼①行,語句是sqlite3_open([writableDBPath UTF8String], &db),sqlite3_open函數的第1個參數是數據庫文件完整的路徑,但是需要注意的是在SQLite3函數中接受的是char*的UTF-8類型數據,需要將NSString*轉換為UTF-8,使用NSString*的UTF8String方法可以轉換,sqlite3_open函數第2個參數sqlite3指針變量db的地址。該函數的返回值是int類型,在SQLite3中定義了很多常量,返回值等於常量SQLITE_OK則說明操作成功。

第2步執行建表語句,代碼第④行,語句sqlite3_exec(db,[createSQL UTF8String],NULL,NULL,&err)執行建表的SQL。第1個參數是sqlite3指針變量db的地址,第2個參數是要執行的sql語句,第3個參數是要回調函數,第4個參數是要回調函數的參數,第5個參數是執行出錯的字符串。建表SQL語句是,如果表Note存在這不用創建。

CREATE TABLE IF NOT EXISTS Note (cdate TEXT PRIMARY KEY, content TEXT)

第3步使用sqlite3_close函數釋放資源,代碼②、⑤、⑦行所示,在數據庫打開失敗、Create Table執行失敗和成功執行完成時候調用。原則上無論正常結束還是異常結束必須使用sqlite3_close函數釋放資源。

查詢數據

數據查詢一般會帶有查詢條件,這個使用SQL語句where子句很容易實現,但是在程序中需要動態綁定參數給where子句。執行查詢數據步驟如下:

1、使用sqlite3_open函數打開數據庫;

2、使用sqlite3_prepare_v2函數預處理SQL語句;

3、使用sqlite3_bind_text函數綁定參數;

4、使用sqlite3_step函數執行SQL語句,遍曆結果集;

5、使用sqlite3_column_text等函數提取字段數據;

6、使用sqlite3_finalize和sqlite3_close函數釋放資源。

NoteDAO.m中的按照主鍵查詢數據方法:

-(Note*) findById:(Note*)model

{

NSString *path = [self applicationDocumentsDirectoryFile];

if (sqlite3_open([path UTF8String], &db) != SQLITE_OK) { ①

sqlite3_close(db);  ②

NSAssert(NO,@”數據庫打開失敗。”);

} else {

 

NSString *qsql = @”SELECT cdate,content FROM Note where cdate =?”;

 

sqlite3_stmt *statement;

//預處理過程

if (sqlite3_prepare_v2(db, [qsql UTF8String], -1, &statement, NULL) == SQLITE_OK) { ③

//準備參數

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; ④

[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

NSString *nsdate = [dateFormatter stringFromDate:model.date];

//綁定參數開始

sqlite3_bind_text(statement, 1, [nsdate UTF8String], -1, NULL); ⑤

//執行

if (sqlite3_step(statement) == SQLITE_ROW) { ⑥

char *cdate = (char *) sqlite3_column_text(statement, 0); ⑦

NSString *nscdate = [[NSString alloc] initWithUTF8String: cdate];

 

char *content = (char *) sqlite3_column_text(statement, 1);

NSString * nscontent = [[NSString alloc] initWithUTF8String: content];

Note* note = [[Note alloc] init];

note.date = [dateFormatter dateFromString:nscdate];

note.content = nscontent;

 

sqlite3_finalize(statement);

sqlite3_close(db);

return note;

}

}

 

sqlite3_finalize(statement); ⑧

sqlite3_close(db);  ⑨

 

}

return nil;

}


該方法執行了6個步驟,其中第1個步驟,代碼第①行所示,它與創建數庫的第1個步驟是一樣的,不用再介紹了。

第2個步驟,代碼第③行所示,語句sqlite3_prepare_v2(db, [qsql UTF8String], -1, &statement, NULL)是預處理SQL語句,預處理目的是將SQL編譯成二進製代碼,提高SQL語句執行的速度。sqlite3_prepare_v2函數的第3個參數-1代表全部sql字符串長度,第4個參數&statement是sqlite3_stmt指針的地址,它是語句對象,通過語句對象可以執行SQL語句,第5個參數是sql語句沒有被執行的部分語句。

第3個步驟,代碼第⑤行所示,語句sqlite3_bind_text(statement, 1, [nsdate UTF8String], -1, NULL)是綁定SQL語句參數。在SQL語句中帶有問號,這個問號就是要綁定的參數,問號是占位符。

NSString *qsql = @”SELECT cdate,content FROM Note where cdate =?”;

sqlite3_bind_text函數是綁定參數,第1個參數是statement指針,第2個參數為序號(從1開始),第3個參數為字符串值,第4個參數為字符串長度,第5個參數為一個函數指針。

第4個步驟sqlite3_step(statement)執行SQL語句,代碼第⑥行所示,sqlite3_step返回int類型,等於SQLITE_ROW說明還要其它的行沒有遍曆。

第5個步驟提取字段數據,代碼第⑦行所示,使用sqlite3_column_text(statement, 0)函數可以讀取字符串類型字段,第2參數是指定select字段的索引(從0開始)。同樣char*轉換成為NSString*類型,需要initWithUTF8String:構造方法。讀取字段函數采用與字段類型有關係,SQLite3的類似的常用函數還有:

sqlite3_column_blob()

sqlite3_column_double()

sqlite3_column_int()

sqlite3_column_int64()

sqlite3_column_text()

sqlite3_column_text16()

關於其它的API可以參考https://www.sqlite.org/cintro.html。

第6個步驟是釋放資源,創建數據庫過程不同,除了使用sqlite3_close函數關閉數據庫,代碼第⑧行所示,還要使用sqlite3_finalize函數釋放語句對象statement代碼第⑨行所示。

NoteDAO.m中的查詢所有數據方法:

-(NSMutableArray*) findAll

{

NSString *path = [self applicationDocumentsDirectoryFile];

NSMutableArray *listData = [[NSMutableArray alloc] init];

if (sqlite3_open([path UTF8String], &db) != SQLITE_OK) {

sqlite3_close(db);

NSAssert(NO,@”數據庫打開失敗。”);

} else {

 

NSString *qsql = @”SELECT cdate,content FROM Note”;

 

sqlite3_stmt *statement;

//預處理過程

if (sqlite3_prepare_v2(db, [qsql UTF8String], -1, &statement, NULL) == SQLITE_OK) {

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

//執行

while (sqlite3_step(statement) == SQLITE_ROW) {

char *cdate = (char *) sqlite3_column_text(statement, 0);

NSString *nscdate = [[NSString alloc] initWithUTF8String: cdate];

 

char *content = (char *) sqlite3_column_text(statement, 1);

NSString * nscontent = [[NSString alloc] initWithUTF8String: content];

Note* note = [[Note alloc] init];

note.date = [dateFormatter dateFromString:nscdate];

note.content = nscontent;

[listData addObject:note];

}

}

 

sqlite3_finalize(statement);

sqlite3_close(db);

 

}

return listData;

}


查詢所有數據方法與按照主鍵查詢數據方法類似,區別在於本方法沒有查詢條件不需要綁定參數。遍曆的時候使用while循環語句,不是if語句。

while (sqlite3_step(statement) == SQLITE_ROW) {

… …

}

修改數據 

修改數據包括:insert、update和delete語句。這3個SQL語句都可以帶有參數,關於參數的綁定與查詢where子句綁定的方式是一樣的。執行修改數據步驟如下:

1、使用sqlite3_open函數打開數據庫;

2、使用sqlite3_prepare_v2函數預處理SQL語句;

3、使用sqlite3_bind_text函數綁定參數;

4、使用sqlite3_step函數執行SQL語句;

5、使用sqlite3_finalize和sqlite3_close函數釋放資源。

修改數據的步驟與查詢數據的步驟相比少了一個提取字段數據步驟。下麵我們看看代碼部分。其它的步驟是一樣的。

NoteDAO.m中的插入Note方法:

-(int) create:(Note*)model

{

NSString *path = [self applicationDocumentsDirectoryFile];

if (sqlite3_open([path UTF8String], &db) != SQLITE_OK) { ①

sqlite3_close(db);  ②

NSAssert(NO,@”數據庫打開失敗。”);

} else {

 

NSString *sqlStr = @”INSERT OR REPLACE INTO note (cdate, content) VALUES (?,?)”;

 

sqlite3_stmt *statement;

//預處理過程

if (sqlite3_prepare_v2(db, [sqlStr UTF8String], -1, &statement, NULL) == SQLITE_OK) { ③

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

NSString *nsdate = [dateFormatter stringFromDate:model.date];

//綁定參數開始

sqlite3_bind_text(statement, 1, [nsdate UTF8String], -1, NULL);  ④

sqlite3_bind_text(statement, 2, [model.content UTF8String], -1, NULL);

 

//執行插入

if (sqlite3_step(statement) != SQLITE_DONE) { ⑤

NSAssert(NO, @”插入數據失敗。”);

}

}

 

sqlite3_finalize(statement);  ⑥

sqlite3_close(db);  ⑦

}

return 0;

}


第⑤行代碼sqlite3_step(statement)語句執行插入語句,常量SQLITE_DONE執行完成。

NoteDAO.m中的刪除Note方法:

-(int) remove:(Note*)model

{

NSString *path = [self applicationDocumentsDirectoryFile];

if (sqlite3_open([path UTF8String], &db) != SQLITE_OK) {

sqlite3_close(db);

NSAssert(NO,@”數據庫打開失敗。”);

} else {

 

NSString *sqlStr = @”DELETE  from note where cdate =?”;

 

sqlite3_stmt *statement;

//預處理過程

if (sqlite3_prepare_v2(db, [sqlStr UTF8String], -1, &statement, NULL) == SQLITE_OK) {

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

NSString *nsdate = [dateFormatter stringFromDate:model.date];

//綁定參數開始

sqlite3_bind_text(statement, 1, [nsdate UTF8String], -1, NULL);

//執行插入

if (sqlite3_step(statement) != SQLITE_DONE) {

NSAssert(NO, @”刪除數據失敗。”);

}

}

 

sqlite3_finalize(statement);

sqlite3_close(db);

}

return 0;

}

NoteDAO.m中的修改Note方法:

-(int) modify:(Note*)model

{

NSString *path = [self applicationDocumentsDirectoryFile];

if (sqlite3_open([path UTF8String], &db) != SQLITE_OK) {

sqlite3_close(db);

NSAssert(NO,@”數據庫打開失敗。”);

} else {

 

NSString *sqlStr = @”UPDATE note set content=? where cdate =?”;

 

sqlite3_stmt *statement;

//預處理過程

if (sqlite3_prepare_v2(db, [sqlStr UTF8String], -1, &statement, NULL) == SQLITE_OK) {

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

NSString *nsdate = [dateFormatter stringFromDate:model.date];

//綁定參數開始

sqlite3_bind_text(statement, 1, [model.content UTF8String], -1, NULL);

sqlite3_bind_text(statement, 2, [nsdate UTF8String], -1, NULL);

//執行插入

if (sqlite3_step(statement) != SQLITE_DONE) {

NSAssert(NO, @”修改數據失敗。”);

}

}

 

sqlite3_finalize(statement);

sqlite3_close(db);

}

return 0;

}


最後更新:2017-04-03 16:48:34

  上一篇:go 奔騰的芯:Intel
  下一篇:go Windows的定時任務(Schedule Task)設置