轉載自唐巧的博客,怕資源丟失故轉載到自己簡書,原文點這里
前言
SQLite 是一個輕量級的關系數據庫。iOS SDK 很早就支持了 SQLite,在使用時,只需要加入 libsqlite3.dylib 依賴以及引入 sqlite3.h 頭文件即可。但是,原生的 SQLite API 在使用上相當不友好,在使用時,非常不便。于是,開源社區中就出現了一系列將 SQLite API 進行封裝的庫,而 FMDB 則是開源社區中的優秀者。
FMDB 在使用上相當方便。以下是一個簡單的例子:
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 后的數據庫代碼清晰明了,比原生的 API 優雅多了。另外,FMDB 同時兼容 ARC 和非 ARC 工程,會自動根據工程配置來調整相關的內存管理代碼。
使用說明
該使用說明主要翻譯自 fmdb 的 github 項目說明文檔
引入相關文件
首先將 FMDB 從 github 上 clone 下來,然后將以下文件 copy 到你的工程中:
FMDatabase.h
FMDatabase.m
FMDatabaseAdditions.h
FMDatabaseAdditions.m
FMDatabasePool.h
FMDatabasePool.m
FMDatabaseQueue.h
FMDatabaseQueue.m
FMResultSet.h
FMResultSet.m
建立數據庫
建立數據庫只需要如下一行即可 , 當該文件不存在時,fmdb 會自己創建一個。如果你傳入的參數是空串:@”” ,則 fmdb 會在臨時文件目錄下創建這個數據庫,如果你傳入的參數是 NULL,則它會建立一個在內存中的數據庫。
FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
打開數據庫
使用如下語句,如果打開失敗,可能是權限不足或者資源不足。通常打開完操作操作后,需要調用 close 方法來關閉數據庫。
if (![db open]) {
// error
return;
}
// some operation
// ...
[db close];
執行更新操作
除了 Select 操作之外,其它的都是更新操作。更新操作使用如下方法,如果有錯誤,可以用 error 參數中獲得。
-[FMDatabase executeUpdate:error:withArgumentsInArray:orVAList:]
執行查詢操作
查詢操作示例如下。注意:即使操作結果只有一行,也需要先調用 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 提供如下多個方法來獲取不同類型的數據:
intForColumn:
longForColumn:
longLongIntForColumn:
boolForColumn:
doubleForColumn:
stringForColumn:
dateForColumn:
dataForColumn:
dataNoCopyForColumn:
UTF8StringForColumnIndex:
objectForColumn:
通常情況下,你并不需要關閉 FMResultSet,因為相關的數據庫關閉時,FMResultSet 也會被自動關閉。
數據參數
通常情況下,你可以按照標準的 SQL 語句,用 ? 表示執行語句的參數,如:
INSERT INTO myTable VALUES (?, ?, ?)
然后,可以我們可以調用 executeUpdate 方法來將 ? 所指代的具體參數傳入,通常是用變長參數來傳遞進去的,如下:
NSString *sql = @"insert into User (name, password) values (?, ?)";
[db executeUpdate:sql, user.name, user.password];
這里需要注意的是,參數必須是 NSObject 的子類,所以象 int,double,bool 這種基本類型,需要封裝成對應的包裝類才行,如下所示:
// 錯誤,42 不能作為參數
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", 42];
// 正確,將 42 封裝成 NSNumber 類
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:42]];
線程安全
如果我們的 app 需要多線程操作數據庫,那么就需要使用 FMDatabaseQueue 來保證線程安全了。
切記不能在多個線程中共同一個 FMDatabase 對象并且在多個線程中同時使用,這個類本身不是線程安全的,這樣使用會造成數據混亂等問題。
使用 FMDatabaseQueue 很簡單,首先用一個數據庫文件地址來初使化 FMDatabaseQueue,然后就可以將一個閉包 (block) 傳入 inDatabase 方法中。
在閉包中操作數據庫,而不直接參與 FMDatabase 的管理。
// 創建,最好放在一個單例的類中
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]) {
// …
}
}];
// 如果要支持事務
[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 中的數據,一個好的圖形化界面的數據庫管理程序是必不可少的。mysql 有 phpMyAdmin,那么 sqlite 呢?
我主要使用的是 Firefox 的一個名為 SQLite Manager 的插件,安裝此插件后,可以直接打開后綴名為 sqlite 的數據庫文件。SQLite Manager 提供一個圖形化的界面來執行數據查詢或更改操作。如下圖所示:
總結
FMDB 將 SQLite API 進行了很友好的封裝,使用上非常方便,對于那些使用純 Sqlite API 來進行數據庫操作的 app,可以考慮將其遷移到基于 FMDB 上,這對于以后數據庫相關功能的開發維護,可以提高不少效率。
唐巧在學習 fmdb 的時候做了一個小工程用于練習,把它放到 github 上了。感興趣的可以自行下載:https://github.com/tangqiaoboy/FmdbSample