大家好我是你們的顏大人
<p>由于FMDB是建立在SQLite的之上的,所以你至少也該把這篇文章從頭到尾讀一遍。與此同時(shí)借帘,把SQLite的文檔頁 加到你的書簽中洋措。自動引用計(jì)數(shù)(APC)還是手動內(nèi)存管理呢济蝉?</p>
<p>兩種都行,F(xiàn)MDB會在編譯的時(shí)候知道你是用的哪一種菠发,然后進(jìn)行相應(yīng)處理王滤。</p>
<h4>使用方法</h4>
<h5>FMDB有三個主要的類</h5>
1.FMDatabase – 表示一個單獨(dú)的SQLite數(shù)據(jù)庫。 用來執(zhí)行SQLite的命令滓鸠。
2.FMResultSet – 表示FMDatabase執(zhí)行查詢后結(jié)果集
3.FMDatabaseQueue – 如果你想在多線程中執(zhí)行多個查詢或更新雁乡,你應(yīng)該使用該類。這是線程安全的糜俗。
<h5>數(shù)據(jù)庫創(chuàng)建</h5>
創(chuàng)建FMDatabase對象時(shí)參數(shù)為SQLite數(shù)據(jù)庫文件路徑蔗怠。該路徑可以是以下三種之一:
1..文件路徑墩弯。該文件路徑無需真實(shí)存,如果不存在會自動創(chuàng)建寞射。
2..空字符串(@””)渔工。表示會在臨時(shí)目錄創(chuàng)建一個空的數(shù)據(jù)庫,當(dāng)FMDatabase 鏈接關(guān)閉時(shí)桥温,文件也被刪除引矩。
3.NULL. 將創(chuàng)建一個內(nèi)在數(shù)據(jù)庫。同樣的侵浸,當(dāng)FMDatabase連接關(guān)閉時(shí)旺韭,數(shù)據(jù)會被銷毀。
(如需對臨時(shí)數(shù)據(jù)庫或內(nèi)在數(shù)據(jù)庫進(jìn)行一步了解掏觉,請繼續(xù)閱讀:<a target="_blank" rel="external">http://www.sqlite.org/inmemorydb.html</a>)
<figure class="highlight gherkin"><table><tr><td class="gutter"><pre><span class="line">1</span>
</pre></td><td class="code"><pre><span class="line">FMDatabase <span class="keyword"></span>db = [FMDatabase databaseWithPath:<span class="comment">@"/tmp/tmp.db"];</span></span>
</pre></td></tr></table></figure>
<h5>打開數(shù)據(jù)庫</h5>
在和數(shù)據(jù)庫交互 之前区端,數(shù)據(jù)庫必須是打開的。如果資源或權(quán)限不足無法打開或創(chuàng)建數(shù)據(jù)庫澳腹,都會導(dǎo)致打開失敗织盼。
<figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span>
<span class="line">2</span>
<span class="line">3</span>
<span class="line">4</span>
</pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (![<span class="keyword">db</span> <span class="keyword">open</span>]) { </span>
<span class="line"> [<span class="keyword">db</span> release]; </span>
<span class="line"> <span class="keyword">return</span>; </span>
<span class="line"> }</span>
</pre></td></tr></table></figure>
<h5>執(zhí)行更新</h5>
一切不是SELECT命令的命令都視為更新。這包括 CREATE, UPDATE, INSERT,ALTER,COMMIT, BEGIN, DETACH, DELETE, DROP, END, EXPLAIN, VACUUM, and REPLACE (等)酱塔。
簡單來說沥邻,只要不是以SELECT開頭的命令都是UPDATE命令。
執(zhí)行更新返回一個BOOL值羊娃。YES表示執(zhí)行成功唐全,否則表示有那些錯誤 。你可以調(diào)用 -lastErrorMessage 和 -lastErrorCode方法來得到更多信息蕊玷。
<h5>執(zhí)行查詢</h5>
SELECT命令就是查詢邮利,執(zhí)行查詢的方法是以 -excuteQuery開頭的。
執(zhí)行查詢時(shí)垃帅,如果成功返回FMResultSet對象延届, 錯誤返回nil. 與執(zhí)行更新相當(dāng),支持使用 NSError參數(shù)挺智。同時(shí)祷愉,你也可以使用 -lastErrorCode和-lastErrorMessage獲知錯誤信息窗宦。
為了遍歷查詢結(jié)果赦颇,你可以使用while循環(huán)。你還需要知道怎么跳到下一個記錄赴涵。使用FMDB媒怯,很簡單實(shí)現(xiàn),就像這樣:
<figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span>
<span class="line">2</span>
<span class="line">3</span>
<span class="line">4</span>
</pre></td><td class="code"><pre><span class="line"><span class="constant">FMResultSet </span>s = [db <span class="symbol">executeQuery:</span>@<span class="string">"SELECT * FROM myTable"</span>]; </span>
<span class="line"><span class="keyword">while</span> ([s <span class="keyword">next</span>]) { </span>
<span class="line"> <span class="regexp">//retrieve</span> values <span class="keyword">for</span> each record </span>
<span class="line">}</span>
</pre></td></tr></table></figure>
你必須一直調(diào)用 -[FMResultSet next] 在你訪問查詢返回值之前髓窜,甚至你只想要一個記錄:
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span>
<span class="line">2</span>
<span class="line">3</span>
<span class="line">4</span>
</pre></td><td class="code"><pre><span class="line">FMResultSet s = [db <span class="string">executeQuery:</span>@<span class="string">"SELECT COUNT() FROM myTable"</span>]; </span>
<span class="line"> <span class="keyword">if</span> ([s next]) { </span>
<span class="line"> <span class="typename">int</span> totalCount = [s <span class="string">intForColumnIndex:</span><span class="number">0</span>]; </span>
<span class="line"> }</span>
</pre></td></tr></table></figure>
FMResultSet 提供了很多方法來獲得所需的格式的值:
intForColumn:
longForColumn:
longLongIntForColumn:
boolForColumn:
doubleForColumn:
stringForColumn:
dataForColumn:
dataNoCopyForColumn:
UTF8StringForColumnIndex:
objectForColumn:
這些方法也都包括 {type}ForColumnIndex 的這樣子的方法扇苞,參數(shù)是查詢結(jié)果集的列的索引位置欺殿。
你無需調(diào)用 [FMResultSet close]來關(guān)閉結(jié)果集, 當(dāng)新的結(jié)果集產(chǎn)生,或者其數(shù)據(jù)庫關(guān)閉時(shí)鳖敷,會自動關(guān)閉脖苏。
關(guān)閉數(shù)據(jù)庫
當(dāng)使用完數(shù)據(jù)庫,你應(yīng)該 -close 來關(guān)閉數(shù)據(jù)庫連接來釋放SQLite使用的資源定踱。
<figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span>
</pre></td><td class="code"><pre><span class="line"><span class="title">[db close]</span><span class="comment">;</span></span>
</pre></td></tr></table></figure>
<h4>事務(wù)</h4>
FMDatabase是支持事務(wù)的棍潘。
<h5>數(shù)據(jù)凈化(數(shù)據(jù)格式化)</h5>
<p>使用FMDB,插入數(shù)據(jù)前崖媚,你不要花時(shí)間審查你的數(shù)據(jù)亦歉。你可以使用標(biāo)準(zhǔn)的SQLite數(shù)據(jù)綁定語法。</p>
<p>INSERT INTO myTable VALUES (?, ?, ?) </p>
<p>SQLite會識別 “?” 為一個輸入的點(diǎn)位符畅哑, 這樣的執(zhí)行會接受一個可變參數(shù)(或者表示為其他參數(shù)肴楷,如NSArray, NSDictionary,或va_list等),會正確為您轉(zhuǎn)義荠呐。</p>
<p>你也可以選擇使用命名參數(shù)語法赛蔫。</p>
<p>INSERT INTO myTable VALUES (:id, :name, :value) </p>
<p>參數(shù)名必須以冒名開頭。SQLite本身支持其他字符直秆,當(dāng)Dictionary key的內(nèi)部實(shí)現(xiàn)是冒號開頭濒募。注意你的NSDictionary key不要包含冒號。</p>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span>
<span class="line">2</span>
</pre></td><td class="code"><pre><span class="line">NSDictionary argsDict = [NSDictionary <span class="string">dictionaryWithObjectsAndKeys:</span>@<span class="string">"My Name"</span>, @<span class="string">"name"</span>, nil]; </span>
<span class="line"> [db <span class="string">executeUpdate:</span>@<span class="string">"INSERT INTO myTable (name) VALUES (:name)"</span> <span class="string">withParameterDictionary:</span>argsDict];</span>
</pre></td></tr></table></figure>
<p>而且圾结,代碼不能這么寫(為什么瑰剃?想想吧。)</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span>
</pre></td><td class="code"><pre><span class="line">[db executeUpdate:@"<span class="operator"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> myTable <span class="keyword">VALUES</span> (?)<span class="string">", @"</span>this has <span class="string">" lots of ' bizarre " quotes '"</span>];</span></span>
</pre></td></tr></table></figure>
<p>你應(yīng)該:</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span>
</pre></td><td class="code"><pre><span class="line">[db executeUpdate:@"<span class="operator"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> myTable <span class="keyword">VALUES</span> (?)<span class="string">", @"</span>this has <span class="string">" lots of ' bizarre "</span> quotes <span class="string">'"];</span></span></span>
</pre></td></tr></table></figure>
<p>提供給 -executeUpdate: 方法的參數(shù)都必須是對象筝野。就像以下的代碼就無法工作晌姚,且會產(chǎn)生崩潰。</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span>
</pre></td><td class="code"><pre><span class="line">[db executeUpdate:@"<span class="operator"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> myTable <span class="keyword">VALUES</span> (?)<span class="string">", 42];</span></span></span>
</pre></td></tr></table></figure>
<p> 正確有做法是把數(shù)字打包成 NSNumber對象</p>
<figure class="highlight clojure"><table><tr><td class="gutter"><pre><span class="line">1</span>
<span class="line">2</span>
</pre></td><td class="code"><pre><span class="line"><span class="collection">[db executeUpdate:@<span class="string">"INSERT INTO myTable VALUES (?)"</span>, </span>
<span class="line"><span class="collection">[NSNumber numberWithInt:42]</span>]</span><span class="comment">;</span></span>
</pre></td></tr></table></figure>
<p>或者歇竟,你可以使用 -executeWithFormat: 挥唠,這是NSString風(fēng)格的參數(shù)</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span>
</pre></td><td class="code"><pre><span class="line">[db executeUpdateWithFormat:@"<span class="operator"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> myTable <span class="keyword">VALUES</span> (%<span class="keyword">d</span>)<span class="string">", 42];</span></span></span>
</pre></td></tr></table></figure>
<p> -executeWithFormat: 的方法的內(nèi)部實(shí)現(xiàn)會幫你封裝數(shù)據(jù), 以下這些修飾符都可以使用: %@, %c, %s, %d, %D,%i, %u, %U, %hi, %hu, %qi, %qu, %f, %g, %ld, %lu, %lld, and %llu. 除此之外的修飾符可能導(dǎo)致無法預(yù)知的結(jié)果焕议。 一些情況下宝磨,你需要在SQL語句中使用 % 字符,你應(yīng)該使用 %%盅安。</p>
<p>使用FMDatabaseQueue 及線程安全
在多個線程中同時(shí)使用一個FMDatabase實(shí)例是不明智的』斤保現(xiàn)在你可以為每個線程創(chuàng)建一個FMDatabase對象。 不要讓多個線程分享同一個實(shí)例别瞭,它無法在多個線程中同時(shí)使用窿祥。 若此,壞事會經(jīng)常發(fā)生蝙寨,程序會時(shí)不時(shí)崩潰晒衩,或者報(bào)告異常嗤瞎,或者隕石會從天空中掉下來砸到你Mac Pro. 總之很崩潰。所以听系,不要初始化FMDatabase對象贝奇,然后在多個線程中使用。請使用 FMDatabaseQueue靠胜,它是你的朋友而且會幫助你弃秆。以下是使用方法:</p>
<p>首先創(chuàng)建隊(duì)列。</p>
<figure class="highlight accesslog"><table><tr><td class="gutter"><pre><span class="line">1</span>
</pre></td><td class="code"><pre><span class="line">FMDatabaseQueue *queue = <span class="string">[FMDatabaseQueue databaseQueueWithPath:aPath]</span>;</span>
</pre></td></tr></table></figure>
<p>這樣使用髓帽。</p>
<figure class="highlight clojure"><table><tr><td class="gutter"><pre><span class="line">1</span>
<span class="line">2</span>
<span class="line">3</span>
<span class="line">4</span>
<span class="line">5</span>
<span class="line">6</span>
<span class="line">7</span>
<span class="line">8</span>
<span class="line">9</span>
</pre></td><td class="code"><pre><span class="line"><span class="collection">[queue inDatabase:^<span class="list">(<span class="keyword">FMDatabase</span> *db)</span> <span class="collection">{ </span>
<span class="line"> <span class="collection">[db executeUpdate:@<span class="string">"INSERT INTO myTable VALUES (?)"</span>, <span class="collection">[NSNumber numberWithInt:1]</span>]</span><span class="comment">; </span></span>
<span class="line"> <span class="collection">[db executeUpdate:@<span class="string">"INSERT INTO myTable VALUES (?)"</span>, <span class="collection">[NSNumber numberWithInt:2]</span>]</span><span class="comment">; </span></span>
<span class="line"> <span class="collection">[db executeUpdate:@<span class="string">"INSERT INTO myTable VALUES (?)"</span>, <span class="collection">[NSNumber numberWithInt:3]</span>]</span><span class="comment">; </span></span>
<span class="line"> FMResultSet *rs = <span class="collection">[db executeQuery:@<span class="string">"select * from foo"</span>]</span><span class="comment">; </span></span>
<span class="line"> while<span class="list">(<span class="collection">[rs next]</span>)</span> <span class="collection">{ </span>
<span class="line"> … </span>
<span class="line"> }</span> </span>
<span class="line">}</span>]</span><span class="comment">;</span></span>
</pre></td></tr></table></figure>
<p>像這樣菠赚,輕松地把簡單任務(wù)包裝到事務(wù)里:</p>
<figure class="highlight clojure"><table><tr><td class="gutter"><pre><span class="line">1</span>
<span class="line">2</span>
<span class="line">3</span>
<span class="line">4</span>
<span class="line">5</span>
<span class="line">6</span>
<span class="line">7</span>
<span class="line">8</span>
<span class="line">9</span>
<span class="line">10</span>
</pre></td><td class="code"><pre><span class="line"><span class="collection">[queue inTransaction:^<span class="list">(<span class="keyword">FMDatabase</span> *db, BOOL *rollback)</span> <span class="collection">{ </span>
<span class="line"> <span class="collection">[db executeUpdate:@<span class="string">"INSERT INTO myTable VALUES (?)"</span>, <span class="collection">[NSNumber numberWithInt:1]</span>]</span><span class="comment">; </span></span>
<span class="line"> <span class="collection">[db executeUpdate:@<span class="string">"INSERT INTO myTable VALUES (?)"</span>, <span class="collection">[NSNumber numberWithInt:2]</span>]</span><span class="comment">; </span></span>
<span class="line"> <span class="collection">[db executeUpdate:@<span class="string">"INSERT INTO myTable VALUES (?)"</span>, <span class="collection">[NSNumber numberWithInt:3]</span>]</span><span class="comment">; </span></span>
<span class="line"> if <span class="list">(<span class="keyword">whoopsSomethingWrongHappened</span>)</span> <span class="collection">{ </span>
<span class="line"> *rollback = YES; return; </span>
<span class="line"> }</span> </span>
<span class="line"> // etc… </span>
<span class="line"> <span class="collection">[db executeUpdate:@<span class="string">"INSERT INTO myTable VALUES (?)"</span>, <span class="collection">[NSNumber numberWithInt:4]</span>]</span><span class="comment">; </span></span>
<span class="line"> }</span>]</span><span class="comment">;</span></span>
</pre></td></tr></table></figure>
<p> FMDatabaseQueue 后臺會建立系列化的G-C-D隊(duì)列,并執(zhí)行你傳給G-C-D隊(duì)列的塊郑藏。這意味著 你從多線程同時(shí)調(diào)用調(diào)用方法衡查,GDC也會按它接收的塊的順序來執(zhí)行。誰也不會吵到誰的腳 必盖,每個人都幸福拌牲。</p>