iOS數(shù)據(jù)庫之FMDB的使用

iOS中原生的SQLite API在使用上相當不友好桐款,在使用時,非常不便佳吞。于是拱雏,就出現(xiàn)了一系列將SQLite API進行封裝的庫,例如FMDB,PlausibleDatabase等.

安裝


使用CocoaPods來安裝FMDB

CocoaPods是Swift和Objective-C Cocoa項目的依賴管理器底扳。它擁有4萬多個庫铸抑,用于超過280萬個應用程序。CocoaPods可以幫助您優(yōu)雅地擴展您的項目衷模。

如果你沒有創(chuàng)建CocoaPods工程,在工程目錄下使用

$ pod init

來初始化項目,在生成的Podfile文件中添加FMDB:

target 'MyApp' do
    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
end

然后執(zhí)行

$ pod install

然后使用新生成的*.xcworkspace工程,而不是*.xcodeproj鹊汛。

用法


在FMDB中有三個主要的類;

  • FMDataase-表示一個SQLite數(shù)據(jù)庫.用于執(zhí)行SQLite語句
  • FMResultSet-表示數(shù)據(jù)庫的查詢結(jié)果
  • FMDatabaseQueue-在多個線程來執(zhí)行查詢和更新時會使用這個類

創(chuàng)建數(shù)據(jù)庫

需要制定一個文件路徑(path)來創(chuàng)建一個給予SQLite的FMDatabase,有以下三種方式可以指定文件路徑:

  • 指定一個文件路徑,如果文件不存在,則自動創(chuàng)建
  • 指定路徑為一個空字符串(@""),使用該方式會創(chuàng)建一個臨時數(shù)據(jù)庫文件,當FMDatabase被關(guān)閉的時候,臨時數(shù)據(jù)庫文件自動被刪除
  • NULL 會在內(nèi)存中創(chuàng)建一個臨時數(shù)據(jù)庫,在FMDatabase被關(guān)閉的時候自動刪除
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"tmp.db"];
FMDatabase *db = [FMDatabase databaseWithPath:path];

打開數(shù)據(jù)庫

在與數(shù)據(jù)庫進行交互之前,我們需要打開數(shù)據(jù)庫,如果沒有足夠的資源或權(quán)限打開和/或創(chuàng)建數(shù)據(jù)庫菇爪,則打開失敗,當打開失敗的時候,把db置為nil.

if(![db open]){
db = nil;
return ;
}

執(zhí)行更新

除了SELECT操作外,SQLite的所有命令都使用executeUpdate消息來執(zhí)行.包括CREATE, UPDATE, INSERT, ALTER, COMMIT, BEGIN, DETACH, DELETE, DROP, END, EXPLAIN, VACUUM,REPLACE等,只要你不是執(zhí)行SELECT語句,就是更新數(shù)據(jù)庫操作.

BOOL succ = [db executeUpdate:sql]; //sql是SQLite命令語句字符串

執(zhí)行更新會返回一個布爾值。返回值YES意味著更新成功執(zhí)行柒昏,返回值NO意味著遇到了一些錯誤∥踝幔可以調(diào)用lastErrorMessagelastErrorCode方法來檢索更多的信息职祷。

執(zhí)行查詢

一個SELECT語句是一個查詢,并通過其中一種-executeQuery...方法執(zhí)行届囚。
如果成功執(zhí)行查詢則返回一個FMResultSet對象有梆,失敗返回nil∫庀担可以使用lastErrorMessagelastErrorCode方法來確定查詢失敗的原因泥耀。
為了迭代你的查詢的結(jié)果,可以用一個while()循環(huán),在循環(huán)中使用next方法來不斷取出結(jié)果.

FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable"];
while ([s next]) {
    //retrieve values for each record
}

即使你只希望查詢一個值也需要使用next方法

FMResultSet * s = [db executeQuery:@“ SELECT COUNT(*)FROM myTable ” ];
if([s next ]){
     int totalCount = [s intForColumnIndex:0 ];
}

FMResultSet有許多方法可以取出數(shù)據(jù):

  • intForColumn:
  • longForColumn:
  • longLongIntForColumn:
  • boolForColumn:
  • doubleForColumn:
  • stringForColumn:
  • dateForColumn:
  • dataForColumn:
  • dataNoCopyForColumn:
  • UTF8StringForColumn:
  • objectForColumn:
    例如,取出一個NSStringname數(shù)據(jù)
NSString *name = [s stringForColumn:@"name"];

每個方法還有一個對應的{type}ForColumnIndex:變量蛔添,用來根據(jù)結(jié)果中列的位置來檢索數(shù)據(jù)痰催,而不是列名。
通常情況下沒有必要手動關(guān)閉FMResultSet對象,因為出現(xiàn)這種情況可以當結(jié)果集被釋放迎瞧,或者數(shù)據(jù)庫被關(guān)閉自動關(guān)閉.

關(guān)閉數(shù)據(jù)庫

當你完成對數(shù)據(jù)庫的查詢和更新時夸溶,你應該close關(guān)閉對FMDatabase連接,這樣SQLite將釋放資源凶硅。

[db close];

事務(Transactions)

FMDatabase可以使用begincommit來包裹一個事務

多個語句的執(zhí)行

FMDatabase可以一次執(zhí)行多個語句和用block進行操作

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;
}];

數(shù)據(jù)

當執(zhí)行在FMDB中執(zhí)行SQL語句,為了數(shù)據(jù)庫的安全,需要使用數(shù)據(jù)綁定語法.

INSERT INTO myTable VLUEA (?,?,?,?)

?字符被SQLite識別為要插入的值的占位符缝裁。

NSInteger identifier = 42;
NSString *name = @"Liam O'Flaherty ";
NSDate *date = [NSDate date];
NSString *comment = nil;

BOOL success = [db executeUpdate:@"INSERT INTO authors (identifier, name, date, comment) VALUES (?, ?, ?, ?)", @(identifier), name, date, comment ?: [NSNull null]];
if (!success) {
    NSLog(@"error = %@", [db lastErrorMessage]);
}

注意:基本數(shù)據(jù)類型(如NSInteger),應該作為一個NSNumber對象,通過一個語法糖@()來完成NSIntegerNSNumber的轉(zhuǎn)變
同樣的SQL中的NULL值應該使用[NSNull null]來代替,如上面實例代碼中的comment,使用comment ?:[NSNull null]來代替nil.

或者,也可以使用命名參數(shù)語法,當傳入一個字典類型的時候尤其適用:

INSERT INTO authors (identifier, name, date, comment) VALUES (:identifier, :name, :date, :comment)

參數(shù)必須以:開頭

NSDictionary *arguments = @{@"identifier": @(identifier), @"name": name, @"date": date, @"comment": comment ?: [NSNull null]};
BOOL success = [db executeUpdate:@"INSERT INTO authors (identifier, name, date, comment) VALUES (:identifier, :name, :date, :comment)" withParameterDictionary:arguments];
if (!success) {
    NSLog(@"error = %@", [db lastErrorMessage]);
}

關(guān)鍵是不應該使用NSString方法stringWithFormat手動將值插入到SQL語句本身。

使用FMDatabaseQueue和線程安全

不要在多個線程中同時使用一個FMDatabase對象足绅。當然每個線程創(chuàng)建一個FMDatabase對象總是可以的.只是不要在線程之間共享一個實例捷绑,而且絕對不能同時在多個線程之間共享。這樣可能導致臟數(shù)據(jù)或者寫入異常.

所以不要實例化一個FMDatabase對象并在多個線程中使用它氢妈。

正確的做法是,實例化一個FMDatabaseQueue對象,并在不同的線程中使用這個對象,FMDatabaseQueue會在不同的線程之間同步和協(xié)調(diào).

首先,創(chuàng)建一個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 *db, BOOL *rollback) {
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @1];
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @2];
    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", @3];

    if (whoopsSomethingWrongHappened) {
        *rollback = YES;
        return;
    }

    // etc ...
}];

注意:FMDatabaseQueue方法的調(diào)用是阻塞的,所以你傳遞的^block,不會在另一個線程上運行.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末粹污,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子允懂,更是在濱河造成了極大的恐慌厕怜,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蕾总,死亡現(xiàn)場離奇詭異粥航,居然都是意外死亡,警方通過查閱死者的電腦和手機生百,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門递雀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蚀浆,你說我怎么就攤上這事缀程∷寻桑” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵杨凑,是天一觀的道長滤奈。 經(jīng)常有香客問我,道長撩满,這世上最難降的妖魔是什么蜒程? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮伺帘,結(jié)果婚禮上昭躺,老公的妹妹穿的比我還像新娘。我一直安慰自己伪嫁,他們只是感情好领炫,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著张咳,像睡著了一般帝洪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上脚猾,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天碟狞,我揣著相機與錄音,去河邊找鬼婚陪。 笑死族沃,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的泌参。 我是一名探鬼主播脆淹,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼沽一!你這毒婦竟也來了盖溺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤铣缠,失蹤者是張志新(化名)和其女友劉穎烘嘱,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蝗蛙,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡蝇庭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了捡硅。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哮内。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖壮韭,靈堂內(nèi)的尸體忽然破棺而出北发,到底是詐尸還是另有隱情纹因,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布琳拨,位于F島的核電站瞭恰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏狱庇。R本人自食惡果不足惜寄疏,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望僵井。 院中可真熱鬧,春花似錦驳棱、人聲如沸批什。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽驻债。三九已至,卻和暖如春形葬,著一層夾襖步出監(jiān)牢的瞬間合呐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工笙以, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留淌实,地道東北人。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓猖腕,卻偏偏與公主長得像拆祈,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子倘感,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容