前言
FMDB是以OC的方式封裝了SQLite的C語言API,使用起來更加面向對象,省去了很多麻煩、冗餘的C語言代碼;對比蘋果自帶的Core Data框架,更加輕量級和靈活;提供了多線程安全的數據庫操作方法,有效地防止數據混亂;FMDB同時兼容ARC和非ARC工程,在編譯的時候會自動根據工程配置來調整相關的內存管理代碼。
使用方法
FMDB有三個主要的類
- FMDatabase 表示一個單獨的SQLite數據庫。 用來執行SQLite的命令。
- FMResultSet 表示FMDatabase執行查詢後的結果集
- FMDatabaseQueue 如果你想在多線程中執行多個查詢或更新,你應該使用該類。這是線程安全的。
數據庫創建
通過指定SQLite數據庫文件路徑來創建FMDatabase對象
FMDatabase *db = [FMDatabase databaseWithPath:path]; if (![db open]) { NSLog(@"數據庫打開失敗!"); }
創建FMDatabase對象時參數爲SQLite數據庫文件路徑。該路徑可以是以下三種之一:
1、具體文件路徑
- 該文件路徑無需真實存,如果不存在會自動創建。
2、空字符串@""
- 表示會在臨時目錄創建一個空的數據庫,當FMDatabase 鏈接關閉時,數據庫文件也被刪除。
3、NULL
- 會創建一個內存中臨時數據庫,當FMDatabase連接關閉時,數據庫會被銷燬
打開數據庫
在和數據庫交互 之前,數據庫必須是打開的。如果資源或權限不足無法打開或創建數據庫,都會導致打開失敗,返回BOOL類型
if (![db open]) { [db release]; return; }
執行更新
- 一切不是SELECT命令的命令都視爲更新。這包括 CREATE, UPDATE, INSERT,ALTER,COMMIT, BEGIN, DETACH, DELETE, DROP, END, EXPLAIN, VACUUM, and REPLACE (等)。
簡單來說,只要不是以SELECT開頭的命令都是UPDATE命令。 - 執行更新返回一個BOOL值。YES表示執行成功,否則表示有那些錯誤 。你可以調用 -lastErrorMessage 和 -lastErrorCode方法來得到更多信息。
使用executeUpdate:方法執行更新
- (BOOL)executeUpdate:(NSString*)sql, ... - (BOOL)executeUpdateWithFormat:(NSString*)format, ... - (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
示例
[db executeUpdate:@"UPDATE t_student SET age = ? WHERE name = ?;", @20, @"Jack"]
執行查詢
SELECT命令就是查詢,執行查詢的方法是以 -excuteQuery開頭的。
查詢方法
- (FMResultSet *)executeQuery:(NSString*)sql, ... - (FMResultSet *)executeQueryWithFormat:(NSString*)format, ... - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments
執行查詢時,如果成功返回FMResultSet對象, 錯誤返回nil. 與執行更新相當,支持使用 NSError**參數。同時,你也可以使用 -lastErrorCode和-lastErrorMessage獲知錯誤信息。
爲了遍歷查詢結果,你可以使用while循環。你還需要知道怎麼跳到下一個記錄。使用FMDB,很簡單實現,就像這樣:
FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable"]; while ([s next]) { //retrieve values for each record }
你必須一直調用 -[FMResultSet next] 在你訪問查詢返回值之前,甚至你只想要一個記錄:
FMResultSet *s = [db executeQuery:@"SELECT COUNT(*) FROM myTable"]; if ([s next]) { int totalCount = [s intForColumnIndex:0]; }
FMResultSet 提供了很多方法來獲得所需的格式的值:
intForColumn:
longForColumn:
longLongIntForColumn:
boolForColumn:
doubleForColumn:
stringForColumn:
dataForColumn:
dataNoCopyForColumn:
UTF8StringForColumnIndex:
objectForColumn:
這些方法也都包括 {type}ForColumnIndex 的這樣子的方法,參數是查詢結果集的列的索引位置。
你無需調用 [FMResultSet close]來關閉結果集, 當新的結果集產生,或者其數據庫關閉時,會自動關閉。
關閉數據庫
當使用完數據庫,你應該 -close 來關閉數據庫連接來釋放SQLite使用的資源。
[db close];
使用FMDatabaseQueue 及線程安全
在多個線程中同時使用一個FMDatabase實例是不明智的。現在你可以爲每個線程創建一個FMDatabase對象。 不要讓多個線程分享同一個實例,它無法在多個線程中同時使用。 若此,壞事會經常發生,程序會時不時崩潰,或者報告異常,或者隕石會從天空中掉下來砸到你Mac Pro. 總之很崩潰。所以,不要初始化FMDatabase對象,然後在多個線程中使用。請使用 FMDatabaseQueue,它是你的朋友而且會幫助你。以下是使用方法:
首先創建隊列
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]]; }];
FMDatabaseQueue將運行在一個序列化隊列塊。所以如果你從多個線程在同一時間調用FMDatabaseQueue的方法,他們將執行他們收到的指令。這樣查詢和更新不會相互影響,每一個都是快樂的。