前言:sqlite 是在移動端作為數(shù)據(jù)cache的一種技術(shù)方式,現(xiàn)在在各種app使用也是極其廣泛.但是,iOS自帶的sqlite使用庫,其api的難用性,易懂性都很讓人頭疼.所以,FMDB作為第三方的sqlite封裝庫,被廣為應(yīng)用.因?yàn)槠涿嫦驅(qū)ο蟮姆绞椒庋b,所以其api也是很通俗易懂的.下面,我就在使用FMDB過程中需要注意的幾點(diǎn)小問題羅列一下.這些問題,可以提高你在使用sqlite的效率,以及安全性.
目錄
1. 創(chuàng)建表
2. 數(shù)據(jù)更新
3. 更改表結(jié)構(gòu)
4. 多線程
下面從這三個方面進(jìn)行闡述.
創(chuàng)建表
這里不談你的表結(jié)構(gòu)怎么設(shè)計.只談你在建表的時候需要注意的幾點(diǎn)信息.可以提升你的查詢效率以及將來的可擴(kuò)展性.
1.1 索引
sqlite,其廣泛使用也是因?yàn)樗峁┝朔奖愕年P(guān)系式的存儲結(jié)構(gòu),以及強(qiáng)大的查詢功能.在建表的時候,一起把索引頁創(chuàng)建完成,
能對你的數(shù)據(jù)查詢提高很高.
NSString* messageTableIndexCreateSql = [NSString stringWithFormat:@"CREATE INDEX IF NOT EXISTS message_index ON %@(sessionid,messageid);",tableName];
[self.dataBase executeUpdate:messageTableIndexCreateSql];
1.2 擴(kuò)展字段
我估計每個人在建表的時候,都會預(yù)留一個擴(kuò)展字段(ext),為以后的表的擴(kuò)展做預(yù)留.我這里再次提一下,其目的是為想展示一下我在這個擴(kuò)展字段里存放的內(nèi)容.
我在這個可擴(kuò)展字段里,放了一段json結(jié)構(gòu)的數(shù)據(jù)串.都可以key-value結(jié)構(gòu)的.一個字段,可以擴(kuò)展成N個字段使用.
數(shù)據(jù)更新
涉及到數(shù)據(jù)庫操作,就設(shè)計到數(shù)據(jù)的更新.包括插入,刪除,更新.
2.1 插入
插入數(shù)據(jù)需要從效率以及安全性上考慮.
效率:
首先要考慮是單條插入,還是多條插入
單條數(shù)據(jù)就直接插入就好了.對于多條數(shù)據(jù)就需要考慮以下幾點(diǎn).
1.這多條數(shù)據(jù)是否具有原子性,一致性,隔離性,持久性.
原子性(Atomicity):確保工作單位內(nèi)的所有操作都成功完成锯梁,否則号胚,事務(wù)會在出現(xiàn)故障時終止豌汇,之前的操作也會回滾到以前的狀態(tài)响谓。
一致性(Consistency):確保數(shù)據(jù)庫在成功提交的事務(wù)上正確地改變狀態(tài)。
隔離性(Isolation):使事務(wù)操作相互獨(dú)立和透明笨觅。
持久性(Durability):確保已提交事務(wù)的結(jié)果或效果在系統(tǒng)發(fā)生故障的情況下仍然存在散吵。
如果滿足以上幾點(diǎn),那我們就需要考慮事務(wù).(Transaction),在FMDB中提供的事務(wù)的操作.
- (BOOL)rollback;
- (BOOL)commit;
- (BOOL)beginTransaction;
舉個列子,你有10條數(shù)據(jù),如果需要這10條數(shù)據(jù),需要同時入庫.如果其中一條失敗其余數(shù)據(jù)也不能入庫,這樣的話,就使用事務(wù).當(dāng)失敗的話,rollback到最初狀態(tài).
插入數(shù)據(jù)的時候,最好不用insert.改用replace. 因?yàn)檫@個關(guān)鍵字執(zhí)行的操作是delete + insert. 如果原來有數(shù)據(jù)存在,他會把原來的數(shù)據(jù)delete,然后在插入.
這樣做的好處是,如果原來存在數(shù)據(jù),你要是用insert的話,如果主鍵一致.會導(dǎo)致你insert失敗.還有一個好處是,可以達(dá)到update的效果.
安全:
如果你設(shè)計的表的字段的類型是string,而且這個字段所需要插入的數(shù)據(jù)來自用戶輸入.滿足這兩個條件,你就需要考慮到sql注入了.(具體什么sql注入自行g(shù)oogle)
怎么解決呢?
有兩種方式:
1.自己把所有的要插入的sql語句統(tǒng)一把' 替換成 ''
[value.content stringByReplacingOccurrencesOfString:@"'" withString:@"''"]
2.調(diào)用sqlite原始的格式字符串的api.吐個槽.FMDB,沒有帶格式化sql的api.
sqlite3_mprintf
** Because the %q format string is used, the '\'' character in zText ** is escaped and the SQL generated is as follows: ** ** <blockquote><pre> ** INSERT INTO table1 VALUES('It''s a happy day!') ** </pre></blockquote> **
以上兩種方式都可以.
更改表結(jié)構(gòu)
這個話題,我想是所有的程序員都不愿意看到的.因?yàn)榻K端的版本一旦發(fā)出去,那就意味不能修改了.如果在產(chǎn)品初期,需要不定的情況,我想沒有人能設(shè)計出來應(yīng)變所有變化的表結(jié)構(gòu).
即使留有我上面提到的可擴(kuò)充字段,也不能只靠一個字段解決所有的結(jié)構(gòu)變化.
所以,在終端我的實(shí)現(xiàn)方式是緩存表結(jié)構(gòu).(把表的結(jié)構(gòu)用文本的方式緩存到本地)每次在打開數(shù)據(jù)庫的時候,先讀本地的表結(jié)構(gòu),然后跟代碼中寫的表結(jié)構(gòu)做對比.如果一點(diǎn)發(fā)現(xiàn)不一致.直接drop表.雖說有點(diǎn)暴力,但是影響并不是太大.最壞的結(jié)果是本地的數(shù)據(jù)沒有了(沒關(guān)系,服務(wù)器還有).這樣,最起碼保證程序能夠正常運(yùn)行.
多線程
sqlite本身不是線程安全的.但是FMDB提供了一個FMDatabaseQueue,這個可以解決多線程訪問數(shù)據(jù)的問題.
by the way.我本身沒有用這種方式.我把所有的數(shù)據(jù)訪問都放在一個線程里去做,這樣在不影響整體數(shù)據(jù)訪問,插入效率的情況下,是一種不錯的方式.
或者,還可以自己在最外部創(chuàng)建一個隊列,管理數(shù)據(jù)的插入,刪除.比如用GCD的barrier.