Github 地址: FMDB
由于 SQLite3 使用比較麻煩, 所以推薦使用第三方開源庫FMDB , 他以 OC 的方式封裝了SQLite 的C 語言 API.
優點:
- 使用起來更加面向對象,省去了很多麻煩、冗余的C語言代碼
- 對比蘋果自帶的Core Data框架,更加輕量級和靈活
- 提供了多線程安全的數據庫操作方法,有效地防止數據混亂
核心類
FMDB有三個主要的類:
- FMDatabase
一個FMDatabase對象就代表一個單獨的SQLite數據庫,用來執行SQL語句
- FMResultSet
使用FMDatabase執行查詢后的結果集
- FMDatabaseQueue
用于在多線程中執行多個查詢或更新,它是線程安全的
打開數據庫
和c語言框架一樣,FMDB通過指定SQLite數據庫文件路徑來創建FMDatabase對象,但FMDB更加容易理解,使用起來更容易,使用之前一樣需要導入sqlite3.dylib
。打開數據庫方法如下:
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.db"];
FMDatabase *database = [FMDatabase databaseWithPath:path];
if (![database open]) {
NSLog(@"數據庫打開失敗!");
}
path
的值可以傳入以下三種:
- 具體文件路徑,如果不存在會自動創建
- 空字符串@"",會在臨時目錄創建一個空的數據庫,當FMDatabase連接關閉時,數據庫文件也被刪除
- nil,會創建一個內存中臨時數據庫,當FMDatabase連接關閉時,數據庫會被銷毀
更新
在FMDB中,除查詢以外的所有操作,都稱為“更新”, 如:create
、drop
、insert
、update
、delete
等操作,使用executeUpdate:
方法執行更新:
//常用方法有以下3種:
- (BOOL)executeUpdate:(NSString*)sql, ...
- (BOOL)executeUpdateWithFormat:(NSString*)format, ...
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments
//示例
[database executeUpdate:@"CREATE TABLE IF NOT EXISTS t_person(id integer primary key autoincrement, name text, age integer)"];
//或者
[database executeUpdate:@"INSERT INTO t_person(name, age) VALUES(?, ?)", @"Bourne", [NSNumber numberWithInt:42]];
查詢
- (FMResultSet *)executeQuery:(NSString*)sql, ...
- (FMResultSet *)executeQueryWithFormat:(NSString*)format, ...
- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments
例:
FMResultSet *result = [database executeQuery:@"SELECT * FROM t_person"];
//2.遍歷結果集
while ([result next]) {
NSString *name = [result stringForColumn:@"name"];
int age = [result intForColumn:@"age"];
}
CocoaPods
pod 'FMDB'
# pod 'FMDB/FTS' # FMDB with FTS
# pod 'FMDB/standalone' # FMDB with latest SQLite amalgamation source
# pod 'FMDB/standalone/FTS' # FMDB with latest SQLite amalgamation source and FTS
# pod 'FMDB/SQLCipher' # FMDB with SQLCipher
多條語句與批處理
可以將多條語句放在一起執行
NSString *sql = @"create table bulktest1 (id integer primary key autoincrement, x text);"
"create table bulktest2 (id integer primary key autoincrement, y text);"
"create table bulktest3 (id integer primary key autoincrement, z text);"
"insert into bulktest1 (x) values ('XXX');"
"insert into bulktest2 (y) values ('YYY');"
"insert into bulktest3 (z) values ('ZZZ');";
success = [db executeStatements:sql];
sql = @"select count(*) as count from bulktest1;"
"select count(*) as count from bulktest2;"
"select count(*) as count from bulktest3;";
success = [self.db executeStatements:sql withResultBlock:^int(NSDictionary *dictionary) {
NSInteger count = [dictionary[@"count"] integerValue];
XCTAssertEqual(count, 1, @"expected one record for dictionary %@", dictionary);
return 0;
}];
使用FMDataBaseQueue 和線程安全
不要讓多個線程分享同一個FMDatabase實例,它無法在多個線程中同時使用。 如果在多個線程中同時使用一個FMDatabase實例,會造成數據混亂等問題。所以,請使用 FMDatabaseQueue,它是線程安全的。
- 創建隊列
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];
- 使用隊列
[queue inDatabase:^(FMDatabase *db) {
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @1];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @2];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @3];
FMResultSet *rs = [db executeQuery:@"select * from foo"];
while ([rs next]) {
…
}
}];
- 把任務包裝到事務里
[queue inTransaction:^(FMDatabase *database, BOOL *rollback) {
[database executeUpdate:@"INSERT INTO t_person(name, age) VALUES (?, ?)", @"Bourne_1", [NSNumber numberWithInt:1]];
[database executeUpdate:@"INSERT INTO t_person(name, age) VALUES (?, ?)", @"Bourne_2", [NSNumber numberWithInt:2]];
[database executeUpdate:@"INSERT INTO t_person(name, age) VALUES (?, ?)", @"Bourne_3", [NSNumber numberWithInt:3]];
FMResultSet *result = [database executeQuery:@"select * from t_person"];
while([result next]) {
}
//回滾
*rollback = YES;
}];
FMDatabaseQueue 后臺會建立系列化的G-C-D隊列,并執行你傳給G-C-D隊列的塊。這意味著 你從多線程同時調用調用方法,GDC也會按它接收的塊的順序來執行。