iOS --FMDB 使用問題小結(jié)

前言

iOS 開發(fā)中,一些項(xiàng)目可能就需要存儲(chǔ)一些數(shù)據(jù),常用的方式有 NSUserDefaults 荣堰、Plist、NSFileManager 文件讀寫竭翠、NSArchiver 解歸檔振坚、CoreData 等。
在這些存儲(chǔ)方式滿足不了的時(shí)候就要用數(shù)據(jù)了斋扰,移動(dòng)端輕量級(jí)的數(shù)據(jù)庫就是 sqlite 了渡八,嵌入式的數(shù)據(jù)庫,本質(zhì)就是一個(gè)文件传货,但原生的 API 用起來又極其不方便了屎鳍,第三方框架 FMDB 成為了大多數(shù) iOS 開發(fā)者的首選。

說實(shí)話损离,現(xiàn)在接觸的項(xiàng)目可能都沒那么大哥艇,沒那么多數(shù)據(jù)要存儲(chǔ)绝编,這幾年沒怎么用僻澎,只是幾年前用了幾次,但每次總會(huì)遇到一些問題十饥,這不現(xiàn)在又遇到了窟勃,特此記錄一下,供大家參考逗堵,有不對(duì)的請(qǐng)指正:

一秉氧、FMDB 插入數(shù)據(jù)不成功

今天建完表,在插入數(shù)據(jù)的時(shí)候無論也插入不成功蜒秤,一直失敗汁咏,找不到原因亚斋。

當(dāng)你知道原因后真想抽自己一個(gè)大嘴巴子 ,不細(xì)心攘滩。

開始是這樣的帅刊,乍一看,貌似沒有什么問題漂问,

BOOL result = [db executeUpdate:@"INSERT INTO Chat_Conversation (MsgCreateTime, MsgServerTime, MesSendUserID , MsgDirection, MsgContent, MsgStatus, MsgType, ConversationType) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", locTime,serverTimeStamp, isSender?message.toUserId:message.fromUserId, isSender?@1:@0, msgContent, status, @(message.messageType), @(message.conversationType)];

但調(diào)試時(shí)會(huì)發(fā)現(xiàn)有數(shù)據(jù)為 nil, 導(dǎo)致插入失敗赖瞒。

另外一種方法:

NSString *insertSql = [NSString stringWithFormat:@"INSERT INTO Chat_Conversation (MsgCreateTime, MsgServerTime, MesSendUserID, MsgDirection, MsgContent,MsgStatus, MsgType,ConversationType) VALUES (%@, %@, %@, %@, %@, %@, %@, %@)", locTime,serverTimeStamp, sendUId, isSender?@1:@0, msgContent, status, @(message.messageType), @(message.conversationType)];
BOOL result = [db executeUpdate:insertSql];

但是你發(fā)現(xiàn),還是一直失敗蚤假,因?yàn)檫@樣用字符串拼接的話栏饮,字段為字符串的要加上單引號(hào)就好了。

兩種方式磷仰,推薦第一種:

image.png

另外要注意的一點(diǎn)就是:

字段為 Interger 的在插入數(shù)據(jù)的時(shí)候要轉(zhuǎn)換為 NSNumber 類型的才可以袍嬉。

二、FMDB死鎖問題

inDatabase: was called reentrantly on the same queue, which would lead to a deadlock

不能在執(zhí)行一個(gè)fmdbqueue還沒有執(zhí)行完畢的時(shí)候芒划,去執(zhí)行另外一個(gè)fmdbqueue冬竟。
使用fmdb進(jìn)行數(shù)據(jù)庫操作,出現(xiàn)inDatabase: was called reentrantly on the same queue, which would lead to a deadlock這樣的崩潰錯(cuò)誤.原因是在一個(gè)[queue inDataBase]的block中,又執(zhí)行了一個(gè)inDataBase.這時(shí)第一個(gè)block需要執(zhí)行結(jié)束才能出隊(duì)列,第二個(gè)block才能執(zhí)行.但是第一個(gè)block又包含了第二個(gè)block,也就是說第二個(gè)block不執(zhí)行,第一個(gè)block就不能結(jié)束.于是就互相等待,也就是各種死鎖.

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

image.png
image.png
image.png

這個(gè)問題因?yàn)? [self.databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
}]; 中人未執(zhí)行完又執(zhí)行了新的任務(wù),例如插入數(shù)據(jù)時(shí)更新其他表數(shù)據(jù)等民逼,這時(shí)就會(huì)崩潰泵殴。
同上面的線程鎖一樣的,這是多線程訪問數(shù)據(jù)庫導(dǎo)致的 crash拼苍。

在多線程使用 FMDatabaseQueue 的確很安全笑诅,通過 GCD 的串行隊(duì)列來保證所有讀寫操作都是串行執(zhí)行的,但是分析可以看到崩潰發(fā)生在函數(shù) [FMResultSet reset]疮鲫,使用 FMDatabaseQueue 還是發(fā)生了多線程使用同一個(gè)數(shù)據(jù)庫連接吆你、預(yù)處理語句的情況,于是就崩潰了俊犯。

解決方案:
如果用 while 循環(huán)遍歷 FMResultSet 就不存在該問題妇多,因?yàn)?[FMResultSet next] 遍歷到最后會(huì)調(diào)用 [FMResultSet close]。

[_queue inDatabase:^(FMDatabase * _Nonnull db) {
FMResultSet *result = [db executeQuery:@"select * from test where a = '1'"];
// 安全
while ([result next]) {
}

// 安全
if ([result next]) {
}
[result close];

}];
如果一定要用 if ([result next]) 燕侠,手動(dòng)加上 [FMResultSet close] 也沒有問題者祖,這樣操作在多線程訪問修改時(shí)仍然會(huì)。

FMDB線程安全問題

最近在使用 FMDB 操作數(shù)據(jù)庫時(shí)绢彤,總在出現(xiàn)這個(gè)問題七问,頻繁的崩潰,報(bào)錯(cuò)信息如下:

image.png

從在控制臺(tái)能看到報(bào)錯(cuò):
[logging] BUG IN CLIENT OF sqlite3.dylib: illegal multi-threaded access to database connection
一看就知道是線程的問題茫舶,多線程訪問數(shù)據(jù)庫造成的械巡,其實(shí)原因早已經(jīng)都知道了,下面更新代碼的問題:

image.png

原因找到,重要的是要怎么改讥耗,來避免有勾,

image.png

這個(gè)問題比較棘手,嘗試了不少方法古程,但是一直都不好使柠衅。

在 [FMDatabaseQueue inDatabase:] 函數(shù)的最后,調(diào)用 [db closeOpenResultSets] 幫助調(diào)用者關(guān)閉所有 FMResultSet籍琳。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末菲宴,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子趋急,更是在濱河造成了極大的恐慌喝峦,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件呜达,死亡現(xiàn)場離奇詭異谣蠢,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)查近,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門眉踱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人霜威,你說我怎么就攤上這事谈喳。” “怎么了戈泼?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵婿禽,是天一觀的道長。 經(jīng)常有香客問我大猛,道長扭倾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任挽绩,我火速辦了婚禮膛壹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘唉堪。我一直安慰自己模聋,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布巨坊。 她就那樣靜靜地躺著撬槽,像睡著了一般此改。 火紅的嫁衣襯著肌膚如雪趾撵。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音占调,去河邊找鬼暂题。 笑死,一個(gè)胖子當(dāng)著我的面吹牛究珊,可吹牛的內(nèi)容都是我干的薪者。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼剿涮,長吁一口氣:“原來是場噩夢啊……” “哼言津!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起取试,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤悬槽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后瞬浓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體初婆,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年猿棉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了磅叛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡萨赁,死狀恐怖弊琴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情杖爽,我是刑警寧澤访雪,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站掂林,受9級(jí)特大地震影響臣缀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜泻帮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一精置、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧锣杂,春花似錦脂倦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至踱蠢,卻和暖如春火欧,著一層夾襖步出監(jiān)牢的瞬間棋电,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來泰國打工苇侵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赶盔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓榆浓,卻偏偏與公主長得像于未,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子陡鹃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

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