在iOS開發(fā)中使用FMDB

轉(zhuǎn)載自唐巧的博客,怕資源丟失故轉(zhuǎn)載到自己簡(jiǎn)書,原文點(diǎn)這里

前言

SQLite 是一個(gè)輕量級(jí)的關(guān)系數(shù)據(jù)庫。iOS SDK 很早就支持了 SQLite,在使用時(shí),只需要加入 libsqlite3.dylib 依賴以及引入 sqlite3.h 頭文件即可。但是,原生的 SQLite API 在使用上相當(dāng)不友好,在使用時(shí),非常不便。于是,開源社區(qū)中就出現(xiàn)了一系列將 SQLite API 進(jìn)行封裝的庫,而 FMDB 則是開源社區(qū)中的優(yōu)秀者。

FMDB 在使用上相當(dāng)方便。以下是一個(gè)簡(jiǎn)單的例子:

NSString* docsdir = [NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString* dbpath = [docsdir stringByAppendingPathComponent:@"user.sqlite"]; 
FMDatabase* db = [FMDatabase databaseWithPath:dbpath];
[db open];
FMResultSet *rs = [db executeQuery:@"select * from people"];
while ([rs next]) {
    NSLog(@"%@ %@",
        [rs stringForColumn:@"firstname"], 
        [rs stringForColumn:@"lastname"]);
}
[db close];

可以看到,使用 FMDB 后的數(shù)據(jù)庫代碼清晰明了,比原生的 API 優(yōu)雅多了。另外,F(xiàn)MDB 同時(shí)兼容 ARC 和非 ARC 工程,會(huì)自動(dòng)根據(jù)工程配置來調(diào)整相關(guān)的內(nèi)存管理代碼。

使用說明

該使用說明主要翻譯自 fmdb 的 github 項(xiàng)目說明文檔

引入相關(guān)文件

首先將 FMDB 從 github 上 clone 下來,然后將以下文件 copy 到你的工程中:

FMDatabase.h
FMDatabase.m
FMDatabaseAdditions.h
FMDatabaseAdditions.m
FMDatabasePool.h
FMDatabasePool.m
FMDatabaseQueue.h
FMDatabaseQueue.m
FMResultSet.h
FMResultSet.m

建立數(shù)據(jù)庫

建立數(shù)據(jù)庫只需要如下一行即可 , 當(dāng)該文件不存在時(shí),fmdb 會(huì)自己創(chuàng)建一個(gè)。如果你傳入的參數(shù)是空串:@”” ,則 fmdb 會(huì)在臨時(shí)文件目錄下創(chuàng)建這個(gè)數(shù)據(jù)庫,如果你傳入的參數(shù)是 NULL,則它會(huì)建立一個(gè)在內(nèi)存中的數(shù)據(jù)庫。

FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];

打開數(shù)據(jù)庫

使用如下語句,如果打開失敗,可能是權(quán)限不足或者資源不足。通常打開完操作操作后,需要調(diào)用 close 方法來關(guān)閉數(shù)據(jù)庫。

if (![db open]) {
    // error 
    return;
}
// some operation
// ...
[db close];

執(zhí)行更新操作

除了 Select 操作之外,其它的都是更新操作。更新操作使用如下方法,如果有錯(cuò)誤,可以用 error 參數(shù)中獲得。

-[FMDatabase executeUpdate:error:withArgumentsInArray:orVAList:]

執(zhí)行查詢操作

查詢操作示例如下。注意:即使操作結(jié)果只有一行,也需要先調(diào)用 FMResultSet 的 next 方法。

FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable"];
while ([s next]) {
    //retrieve values for each record
}
FMResultSet *s = [db executeQuery:@"SELECT COUNT(*) FROM myTable"];
if ([s next]) {
    int totalCount = [s intForColumnIndex:0];
}

FMDB 提供如下多個(gè)方法來獲取不同類型的數(shù)據(jù):

intForColumn:
longForColumn:
longLongIntForColumn:
boolForColumn:
doubleForColumn:
stringForColumn:
dateForColumn:
dataForColumn:
dataNoCopyForColumn:
UTF8StringForColumnIndex:
objectForColumn:

通常情況下,你并不需要關(guān)閉 FMResultSet,因?yàn)橄嚓P(guān)的數(shù)據(jù)庫關(guān)閉時(shí),F(xiàn)MResultSet 也會(huì)被自動(dòng)關(guān)閉。

數(shù)據(jù)參數(shù)

通常情況下,你可以按照標(biāo)準(zhǔn)的 SQL 語句,用 ? 表示執(zhí)行語句的參數(shù),如:

INSERT INTO myTable VALUES (?, ?, ?)

然后,可以我們可以調(diào)用 executeUpdate 方法來將 ? 所指代的具體參數(shù)傳入,通常是用變長參數(shù)來傳遞進(jìn)去的,如下:

NSString *sql = @"insert into User (name, password) values (?, ?)";
[db executeUpdate:sql, user.name, user.password];

這里需要注意的是,參數(shù)必須是 NSObject 的子類,所以象 int,double,bool 這種基本類型,需要封裝成對(duì)應(yīng)的包裝類才行,如下所示:

// 錯(cuò)誤,42 不能作為參數(shù)
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", 42];
// 正確,將 42 封裝成 NSNumber 類
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:42]];

線程安全

如果我們的 app 需要多線程操作數(shù)據(jù)庫,那么就需要使用 FMDatabaseQueue 來保證線程安全了。
切記不能在多個(gè)線程中共同一個(gè) FMDatabase 對(duì)象并且在多個(gè)線程中同時(shí)使用,這個(gè)類本身不是線程安全的,這樣使用會(huì)造成數(shù)據(jù)混亂等問題。

使用 FMDatabaseQueue 很簡(jiǎn)單,首先用一個(gè)數(shù)據(jù)庫文件地址來初使化 FMDatabaseQueue,然后就可以將一個(gè)閉包 (block) 傳入 inDatabase 方法中。
在閉包中操作數(shù)據(jù)庫,而不直接參與 FMDatabase 的管理。

// 創(chuàng)建,最好放在一個(gè)單例的類中
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];
// 使用
[queue inDatabase:^(FMDatabase *db) {
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];
    FMResultSet *rs = [db executeQuery:@"select * from foo"];
    while ([rs next]) {
        // …
    }
}];
// 如果要支持事務(wù)
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];
    if (whoopsSomethingWrongHappened) {
        *rollback = YES;
        return;
    }
    // etc…
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]];
}];

工具

為了查看 Sqlite 中的數(shù)據(jù),一個(gè)好的圖形化界面的數(shù)據(jù)庫管理程序是必不可少的。mysql 有 phpMyAdmin,那么 sqlite 呢?
我主要使用的是 Firefox 的一個(gè)名為 SQLite Manager 的插件,安裝此插件后,可以直接打開后綴名為 sqlite 的數(shù)據(jù)庫文件。SQLite Manager 提供一個(gè)圖形化的界面來執(zhí)行數(shù)據(jù)查詢或更改操作。如下圖所示:


sqlite_manager.jpg

總結(jié)

FMDB 將 SQLite API 進(jìn)行了很友好的封裝,使用上非常方便,對(duì)于那些使用純 Sqlite API 來進(jìn)行數(shù)據(jù)庫操作的 app,可以考慮將其遷移到基于 FMDB 上,這對(duì)于以后數(shù)據(jù)庫相關(guān)功能的開發(fā)維護(hù),可以提高不少效率。
唐巧在學(xué)習(xí) fmdb 的時(shí)候做了一個(gè)小工程用于練習(xí),把它放到 github 上了。感興趣的可以自行下載:https://github.com/tangqiaoboy/FmdbSample

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容