天天看點

sqlite第三方類庫:FMDB使用---2

轉自:http://www.cnblogs.com/kenshincui/p/4077833.html#CoreData

基本使用

相比于SQLite3來說Core Data存在着諸多優勢,它面向對象,開發人員不必過多的關心更多資料庫操作知識,同時它基于ObjC操作,書寫更加優雅等。但是它本身也存在着一定的限制,例如如果考慮到跨平台,則隻能選擇SQLite,因為無論是iOS還是Android都可以使用同一個資料庫,降低了開發成本和維護成本。其次是目前多數ORM架構都存在的性能問題,因為ORM最終轉化為SQL操作,其中牽扯到模型資料轉化,其性能自然比不上直接使用SQL操作資料庫。那麼有沒有更好的選擇呢?答案就是對SQLite進行封裝。

其實通過前面對于SQLite的分析,大家應該已經看到KCDbManager就是對于SQLite封裝的結果,開發人員面對的隻有SQL和ObjC方法,不用過多libsqlite3的C語言API。但它畢竟隻是一個簡單的封裝,還有更多的細節沒有考慮,例如如何處理并發安全性,如何更好的處理事務等。是以,這裡推薦使用第三方架構FMDB,整個架構非常輕量級但又不失靈活性,也是很多企業開發的首選。

1.FMDB既然是對于libsqlite3架構的封裝,自然使用起來也是類似的,使用前也要打開一個資料庫,這個資料庫檔案存在則直接打開否則會建立并打開。這裡FMDB引入了一個FMDatabase對象來表示資料庫,打開資料庫和後面的資料庫操作全部依賴此對象。下面是打開資料庫獲得FMDatabase對象的代碼:

-(void)openDb:(NSString *)dbname{
    //取得資料庫儲存路徑,通常儲存沙盒Documents目錄
    NSString *directory=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    NSLog(@"%@",directory);
    NSString *filePath=[directory stringByAppendingPathComponent:dbname];
    //建立FMDatabase對象
    self.database=[FMDatabase databaseWithPath:filePath];
    //打開資料上
    if ([self.database open]) {
        NSLog(@"資料庫打開成功!");
    }else{
        NSLog(@"資料庫打開失敗!");
    }
}      
注意:dataWithPath中的路徑參數一般會選擇儲存到沙箱中的Documents目錄中;如果這個參數設定為nil則資料庫會在記憶體中建立;如果設定為@””則會在沙箱中的臨時目錄建立,應用程式關閉則檔案删除。

2.對于資料庫的操作跟前面KCDbManager的封裝是類似的,在FMDB中FMDatabase類提供了兩個方法executeUpdate:和executeQuery:分别用于執行無傳回結果的查詢和有傳回結果的查詢。當然這兩個方法有很多的重載這裡就不詳細解釋了。唯一需要指出的是,如果調用有格式化參數的sql語句時,格式化符号使用“?”而不是“%@”、等。下面是兩種情況的代碼片段:

a.無傳回結果

-(void)executeNonQuery:(NSString *)sql{
    //執行更新sql語句,用于插入、修改、删除
    if (![self.database executeUpdate:sql]) {
        NSLog(@"執行SQL語句過程中發生錯誤!");
    }
}      

b.有傳回結果

-(NSArray *)executeQuery:(NSString *)sql{
    NSMutableArray *array=[NSMutableArray array];
    //執行查詢sql語句
    FMResultSet *result= [self.database executeQuery:sql];
    while (result.next) {
        NSMutableDictionary *dic=[NSMutableDictionary dictionary];
        for (int i=0; i<result.columnCount; ++i) {
            dic[[result columnNameForIndex:i]]=[result stringForColumnIndex:i];
        }
        [array addObject:dic];
    }
    return array;
}      

對于有傳回結果的查詢而言,查詢完傳回一個遊标FMResultSet,通過周遊遊标進行查詢。而且FMDB中提供了大量intForColumn、stringForColumn等方法進行取值。

并發和事務

我們知道直接使用libsqlite3進行資料庫操作其實是線程不安全的,如果遇到多個線程同時操作一個表的時候可能會發生意想不到的結果。為了解決這個問題建議在多線程中使用FMDatabaseQueue對象,相比FMDatabase而言,它是線程安全的。

建立FMDatabaseQueue的方法是類似的,調用databaseQueueWithPath:方法即可。注意這裡不需要調用打開操作。

-(void)openDb:(NSString *)dbname{
    //取得資料庫儲存路徑,通常儲存沙盒Documents目錄
    NSString *directory=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    NSLog(@"%@",directory);
    NSString *filePath=[directory stringByAppendingPathComponent:dbname];
    //建立FMDatabaseQueue對象
    self.database=[FMDatabaseQueue databaseQueueWithPath:filePath];
}      

然後所有的增删改查操作調用FMDatabaseQueue的inDatabase:方法在block中執行操作sql語句即可。

-(void)executeNonQuery:(NSString *)sql{
    //執行更新sql語句,用于插入、修改、删除
    [self.database inDatabase:^(FMDatabase *db) {
        [db executeUpdate:sql];
    }];
}
-(NSArray *)executeQuery:(NSString *)sql{
    NSMutableArray *array=[NSMutableArray array];
    [self.database inDatabase:^(FMDatabase *db) {
        //執行查詢sql語句
        FMResultSet *result= [db executeQuery:sql];
        while (result.next) {
            NSMutableDictionary *dic=[NSMutableDictionary dictionary];
            for (int i=0; i<result.columnCount; ++i) {
                dic[[result columnNameForIndex:i]]=[result stringForColumnIndex:i];
            }
            [array addObject:dic];
        }
    }];
    return array;
}      

之是以将事務放到FMDB中去說并不是因為隻有FMDB才支援事務,而是因為FMDB将其封裝成了幾個方法來調用,不用自己寫對應的sql而已。其實在在使用libsqlite3操作資料庫時也是原生支援事務的(因為這裡的事務是基于資料庫的,FMDB還是使用的SQLite資料庫),隻要在執行sql語句前加上“begin transaction;”執行完之後執行“commit transaction;”或者“rollback transaction;”進行送出或復原即可。另外在Core Data中大家也可以發現,所有的增、删、改操作之後必須調用上下文的儲存方法,其實本身就提供了事務的支援,隻要不調用儲存方法,之前所有的操作是不會送出的。在FMDB中FMDatabase有beginTransaction、commit、rollback三個方法進行開啟事務、送出事務和復原事務。