iOS中SQLite使用教程
SQLite,是一款輕型的數(shù)據(jù)庫(kù),是遵守ACID的關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),它的設(shè)計(jì)目標(biāo)是嵌入式的,而且目前已經(jīng)在很多嵌入式產(chǎn)品中使用了它,它占用資源非常的低,在嵌入式設(shè)備中,可能只需要幾百K的內(nèi)存就夠了。它能夠支持Windows/Linux/Unix等等主流的操作系統(tǒng),同時(shí)能夠跟很多程序語(yǔ)言相結(jié)合,比如 Tcl、C#、PHP、Java等,還有ODBC接口,同樣比起Mysql、PostgreSQL這兩款開(kāi)源的世界著名數(shù)據(jù)庫(kù)管理系統(tǒng)來(lái)講,它的處理速度比他們都快。SQLite第一個(gè)Alpha版本誕生于2000年5月。 至今已經(jīng)有14個(gè)年頭,SQLite也迎來(lái)了一個(gè)版本 SQLite 3已經(jīng)發(fā)布。
SQLite的特性
1. ACID事務(wù)
ACID,是指在可靠數(shù)據(jù)庫(kù)管理系統(tǒng)(DBMS)中,事務(wù)(transaction)所應(yīng)該具有的四個(gè)特性:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability). 原子性意味著數(shù)據(jù)庫(kù)中的事務(wù)執(zhí)行是作為原子。即不可再分,整個(gè)語(yǔ)句要么執(zhí)行,要么不執(zhí)行。一致性指數(shù)據(jù)庫(kù)事務(wù)不能破壞關(guān)系數(shù)據(jù)的完整性以及業(yè)務(wù)邏輯上的一致性。例如對(duì)銀行轉(zhuǎn)帳事務(wù),不管事務(wù)成功還是失敗,應(yīng)該保證事務(wù)結(jié)束后ACCOUNTS表中Tom和Jack的存款總額為2000元。事務(wù)的隔離性是多個(gè)用戶(hù)并發(fā)訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)時(shí),數(shù)據(jù)庫(kù)為每一個(gè)用戶(hù)開(kāi)啟的事務(wù),不能被其他事務(wù)的操作數(shù)據(jù)所干擾,多個(gè)并發(fā)事務(wù)之間要相互隔離。持久性是指一個(gè)事務(wù)一旦被提交,它對(duì)數(shù)據(jù)庫(kù)中數(shù)據(jù)的改變就是永久性的,接下來(lái)即使數(shù)據(jù)庫(kù)發(fā)生故障也不應(yīng)該對(duì)其有任何影響。
2. 零配置 – 無(wú)需安裝和管理配置
3.儲(chǔ)存在單一磁盤(pán)文件中的一個(gè)完整的數(shù)據(jù)庫(kù)
4.數(shù)據(jù)庫(kù)文件可以在不同字節(jié)順序的機(jī)器間自由的共享
5.支持?jǐn)?shù)據(jù)庫(kù)大小至2TB
6. 足夠小, 大致13萬(wàn)行C代碼, 4.43M
7. 比一些流行的數(shù)據(jù)庫(kù)在大部分普通數(shù)據(jù)庫(kù)操作要快
8. 簡(jiǎn)單, 輕松的API
9. 包含TCL綁定, 同時(shí)通過(guò)Wrapper支持其他語(yǔ)言的綁定
10. 良好注釋的源代碼, 并且有著90%以上的測(cè)試覆蓋率
11. 獨(dú)立,沒(méi)有額外依賴(lài)
12. 源碼完全的開(kāi)源, 你可以用于任何用途, 包括出售它
13. 支持多種開(kāi)發(fā)語(yǔ)言,C, PHP, Perl, Java, C#,Python, Ruby
SQLite在iOS中的基本使用
在iOS開(kāi)發(fā)中可以用一些SQLite數(shù)據(jù)庫(kù)管理工具,例如SQLiteManager。
接下來(lái)就通過(guò)代碼來(lái)講述iOS中如何使用sqlite
sqlite.h文件的引入
首先是打開(kāi)和關(guān)閉數(shù)據(jù)庫(kù),打開(kāi)和創(chuàng)建數(shù)據(jù)庫(kù)都是sqlite3_open函數(shù),如果filename已經(jīng)創(chuàng)建那就是打開(kāi)。
NSString *filename;//數(shù)據(jù)庫(kù)文件路徑 sqlite3 *database; //sqlite3數(shù)據(jù)庫(kù)句柄的指針 //打開(kāi)數(shù)據(jù)庫(kù) - (int) open{ int rc=sqlite3_open([filename UTF8String], &database); if (rc) { sqlite3_close(database); NSLog(@"open database failed"); } return rc; } //關(guān)閉數(shù)據(jù)庫(kù) - (void) close{ if (database!=NULL) { sqlite3_close(database); } } 接下來(lái)插入、刪除、更新都是用sqlite3_exec函數(shù),記住執(zhí)行語(yǔ)句,必須要先打開(kāi)數(shù)據(jù)庫(kù),完成之后需要關(guān)閉數(shù)據(jù)庫(kù)。 //執(zhí)行 insert,update,delete 等非查詢(xún)SQL語(yǔ)句 - (int)executeNonQuery:(NSString *)sql error:(NSError **)error { int rc; char *errmsg; rc = [self open]; if (rc) { //錯(cuò)誤處理 if (error != NULL) { NSDictionary *eDict = [NSDictionary dictionaryWithObject:@"open database failed" forKey:NSLocalizedDescriptionKey]; *error = [NSError errorWithDomain:kSqliteErrorDomain code:rc userInfo:eDict]; } return rc; } rc = sqlite3_exec(database, [sql UTF8String], NULL, NULL, &errmsg); if (rc != SQLITE_OK) { if (error != NULL) { NSDictionary *eDict = [NSDictionary dictionaryWithObject:@"exec sql error" forKey:NSLocalizedDescriptionKey]; *error = [NSError errorWithDomain:kSqliteErrorDomain code:rc userInfo:eDict]; } NSLog(@"%s", errmsg); sqlite3_free(errmsg); } [self close]; return rc; }
上面函數(shù)中sqlite3_free就是釋放存放錯(cuò)誤信息的內(nèi)存空間。查詢(xún)操作會(huì)略顯復(fù)雜,同樣需要有開(kāi)關(guān)數(shù)據(jù)庫(kù)的操作,不過(guò)有一個(gè)準(zhǔn)備結(jié)果集和最后釋放結(jié)果集的操作,分別是sqlite3_prepare_v2和sqlite3_finalize,sqlite3_stmt就是結(jié)果集,下面就是具體操作。
[self open]; // 查 strsql = "select * from users"; // SQLITE_API int sqlite3_prepare_v2( // sqlite3 *db, /* Database handle */ // const char *zSql, /* SQL statement*/ // int nByte, /* 結(jié)果集的最大長(zhǎng)度。*/ // sqlite3_stmt **ppStmt, /* OUT: 結(jié)果集 */ // const char **pzTail /* OUT:指向結(jié)果集沒(méi)有用到的內(nèi)存部分的指針。 */ // ); sqlite3_stmt* rc;//陳述式句柄 if (sqlite3_prepare_v2(db, strsql, -1, &rc, NULL)!=SQLITE_OK) { } // sqlite3_step講結(jié)果集數(shù)據(jù)指針指向下一個(gè)元素。 // 這個(gè)函數(shù)的返回值如果是SQLITE_ROW就表示我們的結(jié)果集里面有數(shù)據(jù)。 // 否則我們的結(jié)果集就是空的。 while (sqlite3_step(rc)==SQLITE_ROW) { // sqlite3_column系列函數(shù)。一般有兩個(gè)輸入?yún)?shù)。第一個(gè)是結(jié)果集指針,第二是數(shù)據(jù)所在列的序號(hào)。 // 比如我們現(xiàn)在用的sqlite3_column_int和sqlite3_column_text。 printf("id:%d | username:%s | password:%s \n",sqlite3_column_int(rc, 0),sqlite3_column_text(rc, 1),sqlite3_column_text(rc, 2)); } // 查完后一定要釋放結(jié)果集。 sqlite3_finalize(rc); [self close];
數(shù)據(jù)庫(kù)加密
免費(fèi)版的SQLite有一個(gè)致命缺點(diǎn):不支持加密。這就導(dǎo)致存儲(chǔ)在SQLite中的數(shù)據(jù)可以被任何人用任何文本編輯器查看到。
對(duì)數(shù)據(jù)庫(kù)加密的思路有兩種:
1. 將內(nèi)容加密后再寫(xiě)入數(shù)據(jù)庫(kù)
這種方式使用簡(jiǎn)單,在入庫(kù)/出庫(kù)只需要將字段做對(duì)應(yīng)的加解密操作即可,一定程度上解決了將數(shù)據(jù)赤裸裸暴露的問(wèn)題。
不過(guò)這種方式并不是徹底的加密,因?yàn)閿?shù)據(jù)庫(kù)的表結(jié)構(gòu)等信息還是能被查看到。另外寫(xiě)入數(shù)據(jù)庫(kù)的內(nèi)容加密后,搜索也是個(gè)問(wèn)題。
2. 對(duì)數(shù)據(jù)庫(kù)文件加密
將整個(gè)數(shù)據(jù)庫(kù)整個(gè)文件加密,這種方式基本上能解決數(shù)據(jù)庫(kù)的信息安全問(wèn)題。目前已有的SQLite加密基本都是通過(guò)這種方式實(shí)現(xiàn)的。這里就介紹一個(gè)開(kāi)源的加密工具SQLCipher,安裝方法可以參照官網(wǎng)文檔,https://www.zetetic.net/sqlcipher/ios-tutorial/,SQLCipher使用256-bit AES加密,由于其基于免費(fèi)版的SQLite,主要的加密接口和SQLite是相同的,但也增加了一些自己的接口。
其實(shí)SQLite的兩個(gè)加密函數(shù)使用起來(lái)非常的簡(jiǎn)單,下面分情況說(shuō)明:
1 給一個(gè)未加密的數(shù)據(jù)庫(kù)添加密碼:如果想要添加密碼,則可以在打開(kāi)數(shù)據(jù)庫(kù)文件之后,關(guān)閉數(shù)據(jù)庫(kù)文件之前的任何時(shí)刻調(diào)用sqlite3_key函數(shù)即可,該函數(shù)有三個(gè)參數(shù),其中第一個(gè)參數(shù)為數(shù)據(jù)庫(kù)對(duì)象,第二個(gè)參數(shù)是要設(shè)定的密碼,第三個(gè)是密碼的長(zhǎng)度。例如:sqlite3_key(db,”1q2w3e4r”,8); //給數(shù)據(jù)庫(kù)設(shè)定密碼1q2w3e4r
2 讀取一個(gè)加密數(shù)據(jù)庫(kù)中的數(shù)據(jù):完成這個(gè)任務(wù)依然十分簡(jiǎn)單,你只需要在打開(kāi)數(shù)據(jù)庫(kù)之后,再次調(diào)用一下sqlite3_key函數(shù)即可,例如,數(shù)據(jù)庫(kù)密碼是123456時(shí),你只需要在代碼中加入sqlite3_key(db,”123456″,6);
3更改數(shù)據(jù)庫(kù)密碼:首先你需要使用當(dāng)前的密碼正確的打開(kāi)數(shù)據(jù)庫(kù),之后你可以調(diào)用sqlite3_rekey(db,”112233″,6) 來(lái)更改數(shù)據(jù)庫(kù)密碼。
4 刪除密碼:也就是把數(shù)據(jù)庫(kù)恢復(fù)到明文狀態(tài)。這時(shí)你仍然只需要調(diào)用sqlite3_rekey函數(shù),并且把該函數(shù)的第二個(gè)參數(shù)置為NULL或者””,或者把第三個(gè)參數(shù)設(shè)為0。
事務(wù)操作
那么問(wèn)題又來(lái)了,如果iOS的sqlite同時(shí)插入或者查詢(xún)10000條數(shù)據(jù),你該怎么辦?
這里有三步要做,第一,減少開(kāi)關(guān)數(shù)據(jù)庫(kù)操作,插入10000條數(shù)據(jù),不能開(kāi)關(guān)10000次數(shù)據(jù)庫(kù),只能進(jìn)行一次開(kāi)關(guān);
第二,就是不能放在主線(xiàn)程;
第三,最重要的一點(diǎn)就是加入事務(wù)操作。
事務(wù)(Transaction)是訪(fǎng)問(wèn)并可能更新數(shù)據(jù)庫(kù)中各種數(shù)據(jù)項(xiàng)的一個(gè)程序執(zhí)行單元(unit)。在sqlite插入數(shù)據(jù)的時(shí)候默認(rèn)一條語(yǔ)句就是一個(gè)事務(wù),有多少條數(shù)據(jù)就有多少次磁盤(pán)操作。所以10000次磁盤(pán)操作可能幾分鐘都做不完,這個(gè)時(shí)候需要把10000條語(yǔ)句都封裝成一個(gè)事務(wù)。
下面就是開(kāi)始事務(wù)和提交事務(wù)的代碼了
-(int)beginService{ char *errmsg; int rc = sqlite3_exec(database, "BEGIN transaction", NULL, NULL, &errmsg); return rc; } -(int)commitService{ char *errmsg; int rc = sqlite3_exec(database, "COMMIT transaction", NULL, NULL, &errmsg); return rc;}
接下來(lái)就把三個(gè)操作合并
-(int)addModelsTest:(NSArray *)models error:(NSError **) error{ char *errmsg; __block NSMutableArray *sqls=[NSMutableArray array]; __block NoticeModel *aModel=[[NoticeModel alloc] init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ for (int i=0; i<100000; i++) { aModel=[models objectAtIndex:0]; NSString *sql=[NSString stringWithFormat:@"insert into notices values('%lf','%d','%@','%@','%@','%d','%d','%d','%d','%@')",aModel.myID,aModel.news_id,aModel.news_title,aModel.content,aModel.pic,aModel.sort,aModel.record_status,aModel.counter,aModel.suid,aModel.publish_time]; [sqls addObject:sql]; } int r1=[self open]; [self beginService]; int rc; int i; for (i=0; i<100000; i++) { rc=sqlite3_exec(database, [[sqls objectAtIndex:i] UTF8String], NULL, NULL, &errmsg); } [self commitService]; [self close]; if (i ==100000) { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"call back, the data is: %@", i); }); } else { NSLog(@"error when download:%@", error); } }); return 0; }
有關(guān)iOS中SQLite使用教程小編就給大家介紹這么多,希望對(duì)大家有所幫助!
- iOS App項(xiàng)目中引入SQLite數(shù)據(jù)庫(kù)的教程
- iOS中sqlite數(shù)據(jù)庫(kù)的原生用法
- iOS中sqlite的詳細(xì)用法
- iOS中SQLite的操作方法
- iOS sqlite對(duì)數(shù)據(jù)庫(kù)的各種操作(日常整理全)
- 簡(jiǎn)介iOS開(kāi)發(fā)中應(yīng)用SQLite的模糊查詢(xún)和常用函數(shù)
- iOS應(yīng)用開(kāi)發(fā)中SQLite的初步配置指南
- iOS開(kāi)發(fā)中使用FMDB來(lái)使程序連接SQLite數(shù)據(jù)庫(kù)
- iOS App使用SQLite之句柄的定義及數(shù)據(jù)庫(kù)的基本操作
相關(guān)文章
iOS實(shí)現(xiàn)點(diǎn)擊狀態(tài)欄自動(dòng)回到頂部效果詳解
在IOS開(kāi)發(fā)過(guò)程中,經(jīng)常會(huì)有這種需求,需要通過(guò)點(diǎn)擊狀態(tài)欄返回到頂部,給用戶(hù)更好的體驗(yàn)效果,下面這篇文章給大家詳細(xì)介紹了實(shí)現(xiàn)過(guò)程,有需要的可以參考借鑒。2016-09-09iOS實(shí)現(xiàn)無(wú)感知上拉加載更多功能的思路與方法
下拉刷新和上拉加載更多功能是一個(gè)應(yīng)用非常廣泛的一個(gè)效果,最新項(xiàng)目中就遇到這個(gè)功能,這篇文章主要給大家介紹了關(guān)于iOS實(shí)現(xiàn)無(wú)感知上拉加載更多功能的思路與方法,需要的朋友可以參考下2021-07-07iOS 委托與文本輸入(內(nèi)容根據(jù)iOS編程編寫(xiě))
這篇文章主要介紹了iOS 委托與文本輸入(內(nèi)容根據(jù)iOS編程編寫(xiě)) 的相關(guān)資料,需要的朋友可以參考下2016-09-09iOS應(yīng)用開(kāi)發(fā)中圖片的拉伸問(wèn)題解決方案
這篇文章主要介紹了iOS應(yīng)用開(kāi)發(fā)中圖片的拉伸問(wèn)題解決方案,有時(shí)圖片的拉伸只需要拉伸中間部分而不拉伸兩端,這是本文所關(guān)注的問(wèn)題,需要的朋友可以參考下2016-02-02解決iOS11圖片下拉放大出現(xiàn)信號(hào)欄白條的bug問(wèn)題
這篇文章主要介紹了iOS11圖片下拉放大出現(xiàn)信號(hào)欄白條的bug問(wèn)題,需要的朋友參考下吧2017-09-09IOS開(kāi)發(fā)仿微信消息長(zhǎng)按氣泡菜單實(shí)現(xiàn)效果
這篇文章主要介紹了IOS開(kāi)發(fā)仿微信消息長(zhǎng)按氣泡菜單實(shí)現(xiàn)效果示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07searchDisplayController 引起的數(shù)組越界處理辦法
這篇文章主要介紹了searchDisplayController 引起的數(shù)組越界處理辦法,需要的朋友可以參考下2015-07-07