
數(shù)據(jù)庫(kù)?
現(xiàn)在重新來(lái)思考數(shù)據(jù)庫(kù)的封裝問(wèn)題,首先就需要弄清楚FMDB數(shù)據(jù)庫(kù)的原理和基本邏輯,首先弄清楚FMDB其實(shí)是一個(gè)封裝的方法庫(kù),因?yàn)閕OS中原生的SQLite API在使用上相當(dāng)不友好,在使用時(shí),非常不便。于是,就出現(xiàn)了一系列將SQLite API進(jìn)行封裝的庫(kù),例如FMDB、PlausibleDatabase、sqlitepersistentobjects等,F(xiàn)MDB是一款簡(jiǎn)潔、易用的封裝庫(kù)。通過(guò)FMDB來(lái)管理SQLite,需要添加libsqlite3.0.dylib這個(gè)框架。FMDB有三個(gè)主要的類1.FMDatabase – 表示一個(gè)單獨(dú)的SQLite數(shù)據(jù)庫(kù)。 用來(lái)執(zhí)行SQLite的命令。2.FMResultSet – 表示FMDatabase執(zhí)行查詢后結(jié)果集 3.FMDatabaseQueue – 如果你想在多線程中執(zhí)行多個(gè)查詢或更新,你應(yīng)該使用該類。這是線程安全的
使用數(shù)據(jù)庫(kù)的第一件事,就是在特定的路徑下建立一個(gè)數(shù)據(jù)庫(kù)。但是要注意的是,iOS環(huán)境下只有document directory 是可以進(jìn)行讀寫(xiě)的。而Resource資料夾底下的東西都是read-only。因此,建立的數(shù)據(jù)庫(kù)必須放在document 資料夾下。創(chuàng)建FMDatabase對(duì)象時(shí),參數(shù)為SQLite數(shù)據(jù)庫(kù)的文件路徑。該路徑可以是以下三種之一:1.文件路徑。該文件路徑無(wú)需真實(shí)存,如果不存在會(huì)自動(dòng)創(chuàng)建。2..空字符串(@”")。表示會(huì)在臨時(shí)目錄創(chuàng)建一個(gè)空的數(shù)據(jù)庫(kù),當(dāng)FMDatabase 鏈接關(guān)閉時(shí),文件也被刪除。3.NULL. 將創(chuàng)建一個(gè)內(nèi)在數(shù)據(jù)庫(kù)。同樣的,當(dāng)FMDatabase連接關(guān)閉時(shí),數(shù)據(jù)會(huì)被銷毀。
[FMDatabase databaseWithPath:]
如果是新建的數(shù)據(jù)庫(kù),一開(kāi)始里面是沒(méi)有類似于Excel表格的。建立Excel表格的方式很簡(jiǎn)單。但在和數(shù)據(jù)庫(kù)交互時(shí),數(shù)據(jù)庫(kù)必須是打開(kāi)狀態(tài)。執(zhí)行更新后都會(huì)返回一個(gè)BOOL值。YES表示執(zhí)行成功,否則就表示出現(xiàn)錯(cuò)誤 。通過(guò)調(diào)用 lastErrorMessage或lastErrorCode方法可以得到更多信息。
那么又回歸到了最本質(zhì)的問(wèn)題,為什么總是感覺(jué)我不會(huì)使用這個(gè)FMDB第三方庫(kù)來(lái)操作原生的SQLite數(shù)據(jù)呢?我是用的太少還是說(shuō)有什么關(guān)鍵的地方?jīng)]有學(xué)到,可是是哪一點(diǎn)沒(méi)有學(xué)好呢?看來(lái)的仔細(xì)排查。首先我知道FMDB是一個(gè)對(duì)原生SQLite數(shù)據(jù)庫(kù)進(jìn)行操作而封裝的庫(kù)。那么作為一個(gè)數(shù)據(jù)庫(kù)來(lái)說(shuō),肯定就是為了存儲(chǔ)東西數(shù)據(jù)嘛!而且通常情況下存儲(chǔ)的都是表格也就是類似于Excel的這種表格。可是如何才能把這種表格的數(shù)據(jù)進(jìn)行方便的操作就是FMDB的意義所在。你可能會(huì)問(wèn),既然里面是以類似于鍵值對(duì)的形式存儲(chǔ)起來(lái),那么為什么不考慮用可變字典來(lái)存儲(chǔ)數(shù)據(jù)呢?對(duì)呀?為什么不適用可變字典呢?問(wèn)題就是字典里的鍵值對(duì)根本不具備數(shù)據(jù)庫(kù)的“增刪改查”的靈活性,而且你還會(huì)發(fā)現(xiàn)一個(gè)區(qū)別就是字典里的鍵不能相同,也就是不能夠存在重復(fù)數(shù)據(jù)的情況。也就是說(shuō):一個(gè)鍵只能對(duì)應(yīng)一個(gè)值,但是數(shù)據(jù)庫(kù)就不一樣了。數(shù)據(jù)庫(kù)的一個(gè)鍵可以對(duì)應(yīng)很多個(gè)值!而且最關(guān)鍵最關(guān)鍵的就是,數(shù)據(jù)里的數(shù)據(jù)是可以全工程共享的。而存在可變字典里的鍵值對(duì),根本很不方便在全工程里使用!
還有對(duì)于一個(gè)表格來(lái)說(shuō)首先就是要?jiǎng)?chuàng)建吧?當(dāng)然工程里的表格是不能直接被創(chuàng)建的,因?yàn)檫@樣就跟字典沒(méi)有什么兩樣了!根本無(wú)法使得這個(gè)存儲(chǔ)數(shù)據(jù)的表格在全工程里被調(diào)用了!所以必須將這個(gè)看似字典其實(shí)更類似于Excel的表格放到一個(gè)數(shù)據(jù)庫(kù)里,而且必須把數(shù)據(jù)庫(kù)放到一個(gè)固定的路徑里。這樣整個(gè)工程都可以根據(jù)這個(gè)數(shù)據(jù)庫(kù)的固定路徑找到數(shù)據(jù)庫(kù)順而找到這個(gè)更類似于Excel的表格。從而就能夠?qū)Ρ砀窭锏臄?shù)據(jù)鍵值對(duì)進(jìn)行編輯了!
好了,現(xiàn)在嘗試一下通過(guò)FMDB如何創(chuàng)建數(shù)據(jù)庫(kù)又如何編輯數(shù)據(jù)庫(kù)里面的表格里的鍵值對(duì)。首先給這個(gè)類輸入一個(gè)路徑參數(shù)固定通過(guò)FMDB的初始化方式實(shí)例化一個(gè)的SQLite數(shù)據(jù)庫(kù)對(duì)象。這里的NSHomeDirectory()就是app應(yīng)用的根地址!然后必須放在根地址的可讀可寫(xiě)的Documents文件夾里,同時(shí)設(shè)置好這個(gè)數(shù)據(jù)庫(kù)的名字叫做data.db。
[[FMDatabase alloc]initWithPath:[NSString stringWithFormat:@"%@/Documents/data.db",NSHomeDirectory()]];
接著判斷已經(jīng)實(shí)例化的對(duì)象的打開(kāi)數(shù)據(jù)庫(kù)方法是否為真,如果為真,就在這個(gè)數(shù)據(jù)庫(kù)里面執(zhí)行對(duì)象的創(chuàng)建表格的方法。create創(chuàng)造一個(gè)表格,名字叫XXX,然后傳入一個(gè)數(shù)組,像是一個(gè)字典中包含所有鍵的數(shù)組。
[對(duì)象 executeUpdate:@"create table 表名(鍵1,鍵2,鍵3)”]
現(xiàn)在表格已經(jīng)創(chuàng)建完成,就可以往表格里面添加?xùn)|西進(jìn)行編輯了,編輯就是增刪改查!首先就是往表格里面添加內(nèi)容,也就是鍵值對(duì)的形式。使用insert插入到表格中所有鍵的值,更像是一個(gè)字典中的值的數(shù)組呀!
[對(duì)象 executeUpdate:@"insert into 表名 values(值1,值2,值3)”]
現(xiàn)在就是刪除表格中滿足特定條件的鍵值對(duì),delete從表格中,判斷的條件就是根據(jù)值來(lái)進(jìn)行分類,只要一個(gè)鍵的值是條件里的限定值,就進(jìn)行刪除操作!
[對(duì)象 executeUpdate:@"delete from 表名 where 鍵1 = ? or 鍵2 = ? or 鍵3 = ?”,限定值,限定值,限定值]
所謂的替換依然使用where來(lái)進(jìn)行條件判斷,如果只要滿足where里的某一類鍵的值的條件,就通過(guò)set來(lái)重新對(duì)這類鍵的值進(jìn)行設(shè)置。
[對(duì)象 executeUpdate:@"update 表名 set 鍵 = ? where 值 > 30(范圍)",替補(bǔ)內(nèi)容]
最后就是通過(guò)FMResultSet創(chuàng)建一個(gè)集合來(lái)接收通過(guò)select來(lái)接收的表格里所有的鍵值對(duì)。但由于這個(gè)result是一個(gè)集合,所以不能使用遍歷,因?yàn)榧项愃朴阪湵?,頭結(jié)點(diǎn)是空的,而且是沒(méi)有順序的。因此通過(guò)While同時(shí)結(jié)合[result next]的方法在While的循環(huán)里每次都判斷[result next]的值是否為空,這樣就可以實(shí)現(xiàn)對(duì)集合的鍵值對(duì)逐行進(jìn)行判斷。同時(shí)在while循環(huán)的遍歷時(shí),通過(guò)創(chuàng)建字符串對(duì)象或其它data數(shù)據(jù)來(lái)接收集合里每一行的所有鍵所對(duì)應(yīng)的值。同時(shí)因?yàn)閿?shù)據(jù)庫(kù)里面的表格里只能存儲(chǔ)string類型和data類型的鍵值對(duì)。所以通常接收也用相應(yīng)地類型。要么NSString,要么NSData。而且這里學(xué)到一個(gè)新東西就是創(chuàng)建一個(gè)數(shù)據(jù)模型的新型方式,先總結(jié)一下過(guò)去創(chuàng)建一個(gè)有值的字典的集中方式,肯定無(wú)一例外首先都是先實(shí)例化一個(gè)對(duì)象,要么在實(shí)例化對(duì)象的時(shí)候就直接給字典里添加鍵值對(duì),要么在實(shí)例化字典對(duì)象之后,在以set方式來(lái)進(jìn)行添加一個(gè)鍵值對(duì),或者以set的方式同時(shí)添加鍵數(shù)組和值數(shù)組。現(xiàn)在再總結(jié)一下過(guò)去只要一面臨很多鍵值對(duì)時(shí),如果想要提取出鍵值對(duì)里面鍵所對(duì)應(yīng)的值,首先想到的方法就是建立一個(gè)數(shù)據(jù)模型,至于為什么要建立一個(gè)數(shù)據(jù)模型好型并沒(méi)有描述。要知道數(shù)據(jù)庫(kù)的表格里面其實(shí)的每一行都相當(dāng)于三個(gè)鍵值對(duì)并排而存在。所以在通過(guò)while和[result next]結(jié)合使用遍歷集合中的每一行時(shí),每一次都相當(dāng)于遍歷一個(gè)字典里的所有鍵值對(duì)。話說(shuō)到這兒,其實(shí)思路也很清晰了,就是其實(shí)數(shù)據(jù)庫(kù)的表格更像是一個(gè)包含許多個(gè)相類似字典的數(shù)組,這才是數(shù)據(jù)庫(kù)的表格的本質(zhì)。那么在遍歷表格里的每一行時(shí)就非常類似于遍歷一個(gè)數(shù)組中的每一個(gè)字典。那么如何才能在不用數(shù)據(jù)模型的情況下接收并存儲(chǔ)原本存儲(chǔ)在表格的每一行的鍵值對(duì)呢?其實(shí)就是將原本設(shè)置在模型.h文件中的模型對(duì)象的屬性現(xiàn)在直接在while的遍歷里進(jìn)行初始化的同時(shí)并將數(shù)據(jù)庫(kù)的表格里的每一行的鍵值對(duì)的鍵對(duì)應(yīng)的值賦值初始化的字符串對(duì)象或Data對(duì)象。然后將初始化的所有對(duì)象名組合成一個(gè)數(shù)組對(duì)象添加到可變數(shù)組中。比較model數(shù)據(jù)模型,這個(gè)while遍歷里本該使用[model setValueWithDictionary:Dict]KVC方法來(lái)對(duì)數(shù)據(jù)模型model對(duì)象的所有屬性進(jìn)行賦值。然后是將model對(duì)象添加到可變數(shù)組中,而不使用數(shù)據(jù)模型時(shí)雖然將原本寫(xiě)在數(shù)據(jù)模型.h文件里的屬性全部移到了while的遍歷循環(huán)里,而且相當(dāng)于在初始化屬性的同時(shí)就將字典鍵對(duì)應(yīng)的值賦值給屬性。那么將這些在While遍歷里創(chuàng)建的屬性組合成一個(gè)數(shù)組對(duì)象然后添加到可變數(shù)組中和那種將數(shù)據(jù)模型對(duì)象添加到可變數(shù)組中,在使用時(shí)有什么不一樣么?當(dāng)然答案肯定是不一樣的,因?yàn)榭勺償?shù)組中添加的是數(shù)據(jù)模型對(duì)象時(shí)想要獲取值是通過(guò)點(diǎn)語(yǔ)法來(lái)實(shí)現(xiàn),而當(dāng)可變數(shù)組中添加的是裝了屬性名的數(shù)組對(duì)象時(shí)想要獲取值必須通過(guò)數(shù)組加下標(biāo)號(hào)來(lái)實(shí)現(xiàn)!不知你有沒(méi)有發(fā)現(xiàn),其實(shí)這就是Model數(shù)據(jù)模型誕生的本質(zhì)!
1、NSHomeDirectory()就是 App Home。包含App bundle的目錄,不要在該路徑下寫(xiě)任何文件。
/Documents/。使用該路徑放置關(guān)鍵數(shù)據(jù),也就是不能通過(guò)App重新生成的數(shù)據(jù)。該路徑可通過(guò)配置實(shí)現(xiàn)iTunes共享文件??杀籭Tunes備份。(現(xiàn)在保存在該路徑下的文件還需要考慮iCloud同步)
/Library/。該路徑下一般保存著用戶配置文件。可創(chuàng)建子文件夾??梢杂脕?lái)放置您希望被備份但不希望被用戶看到的數(shù)據(jù)。該路徑下的文件夾,除Caches以外,都會(huì)被iTunes備份。
/tmp/。使用該路徑保存臨時(shí)文件。App應(yīng)該刪除那些不再被使用的文件,系統(tǒng)也會(huì)在App關(guān)閉后刪除殘留文件。該路徑下的文件不會(huì)被iTunes備份。
5.數(shù)據(jù)源追加后重載數(shù)據(jù)顯示在tableView上,只要對(duì)數(shù)據(jù)庫(kù)編輯后都需要重載數(shù)據(jù),使用完數(shù)據(jù)庫(kù)需要關(guān)閉數(shù)據(jù)庫(kù),如何提高效率呢?數(shù)據(jù)庫(kù)做成一個(gè)單例,在應(yīng)用啟動(dòng)的時(shí)候,就打開(kāi)數(shù)據(jù)庫(kù),當(dāng)進(jìn)入后臺(tái)就關(guān)閉數(shù)據(jù)庫(kù)。
[fm beginTransaction];
[fm rollback];//發(fā)現(xiàn)錯(cuò)誤全部撤銷刪除
[fm commit];// 如果沒(méi)有錯(cuò)誤,則進(jìn)行提交