天天看點

fmdb官方文檔(翻譯) FMDB官方使用文檔  G-C-D的使用  提高性能(翻譯)

FMDB官方使用文檔  G-C-D的使用  提高性能(翻譯)

來自:https://github.com/ccgus/fmdb

由于FMDB是建立在SQLite的之上的,是以你至少也該把這篇文章從頭到尾讀一遍。

與此同時,把SQLite的文檔頁 http://www.sqlite.org/docs.html 加到你的書簽中。

自動引用計數(APC)還是手動記憶體管理呢?

兩種都行,FMDB會在編譯的時候知道你是用的哪一種,然後進行相應處理。

使用方法

FMDB有三個主要的類

    FMDatabase – 表示一個單獨的SQLite資料庫。 用來執行SQLite的指令。

    FMResultSet – 表示FMDatabase執行查詢後結果集

    FMDatabaseQueue – 如果你想在多線程中執行多個查詢或更新,你應該使用該類。這是線程安全的。

資料庫建立

建立FMDatabase對象時參數為SQLite資料庫檔案路徑。該路徑可以是以下三種之一:

檔案路徑。該檔案路徑無需真實存,如果不存在會自動建立。

空字元串(@”")。表示會在臨時目錄建立一個空的資料庫,當FMDatabase 連結關閉時,檔案也被删除。

NULL. 将建立一個内在資料庫。同樣的,當FMDatabase連接配接關閉時,資料會被銷毀。

(如需對臨時資料庫或内在資料庫進行一步了解,請繼續閱讀:http://www.sqlite.org/inmemorydb.html)

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

打開資料庫

在和資料庫互動 之前,資料庫必須是打開的。如果資源或權限不足無法打開或建立資料庫,都會導緻打開失敗。

    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方法來得到更多資訊。

執行查詢

SELECT指令就是查詢,執行查詢的方法是以 -excuteQuery開頭的。

執行查詢時,如果成功傳回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];  

事務

FMDatabase是支援事務的。

資料淨化(資料格式化)

使用FMDB,插入資料前,你不要花時間審查你的資料。你可以使用标準的SQLite資料綁定文法。

    INSERT INTO myTable VALUES (?, ?, ?)  

SQLite會識别 “?” 為一個輸入的點位符, 這樣的執行會接受一個可變參數(或者表示為其他參數,如NSArray, NSDictionary,或va_list等),會正确為您轉義。

你也可以選擇使用命名參數文法。

    INSERT INTO myTable VALUES (:id, :name, :value)  

參數名必須以冒名開頭。SQLite本身支援其他字元,當Dictionary key的内部實作是冒号開頭。注意你的NSDictionary key不要包含冒号。

    NSDictionary *argsDict = [NSDictionary dictionaryWithObjectsAndKeys:@"My Name", @"name", nil];   

    [db executeUpdate:@"INSERT INTO myTable (name) VALUES (:name)" withParameterDictionary:argsDict];  

而且,代碼不能這麼寫(為什麼?想想吧。)

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @"this has \" lots of ' bizarre \" quotes '"];

你應該:

    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @"this has " lots of ' bizarre " quotes '"];  

提供給 -executeUpdate: 方法的參數都必須是對象。就像以下的代碼就無法工作,且會産生崩潰。

    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", 42];  

正确有做法是把數字打包成 NSNumber對象

    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:42]];  

或者,你可以使用  -execute*WithFormat: ,這是NSString風格的參數

    [db executeUpdateWithFormat:@"INSERT INTO myTable VALUES (%d)", 42];  

-execute*WithFormat:  的方法的内部實作會幫你封裝資料, 以下這些修飾符都可以使用: %@, %c, %s, %d, %D,

%i, %u, %U, %hi, %hu, %qi, %qu, %f, %g, %ld, %lu, %lld, and %llu.  除此之外的修飾符可能導緻無法預知的結果。 

一些情況下,你需要在SQL語句中使用 % 字元,你應該使用 %%。

使用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  背景會建立系列化的G-C-D隊列,并執行你傳給G-C-D隊列的塊。這意味着 你從多線程同時調用調用方法,

GDC也會按它接收的塊的順序來執行。誰也不會吵到誰的腳 ,每個人都幸福。