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