SQLite,是一款輕型的數據庫,是遵守ACID的關系型數據庫管理系統,它的設計目標是嵌入式的,而且目前已經在很多嵌入式產品中使用了它,它占用資源非常的低,在嵌入式設備中,可能只需要幾百K的內存就夠了。它能夠支持Windows/Linux/Unix等等主流的操作系統,同時能夠跟很多程序語言相結合,比如 Tcl、C#、PHP、Java等,還有ODBC接口,同樣比起Mysql、PostgreSQL這兩款開源的世界著名數據庫管理系統來講,它的處理速度比他們都快。SQLite第一個Alpha版本誕生於2000年5月。 至今已經有14個年頭,SQLite也迎來了一個版本 SQLite 3已經發布。
SQLite的特性
1. ACID事務
ACID,是指在可靠數據庫管理系統(DBMS)中,事務(transaction)所應該具有的四個特性:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability). 原子性意味著數據庫中的事務執行是作為原子。即不可再分,整個語句要麼執行,要麼不執行。一致性指數據庫事務不能破壞關系數據的完整性以及業務邏輯上的一致性。例如對銀行轉帳事務,不管事務成功還是失敗,應該保證事務結束後ACCOUNTS表中Tom和Jack的存款總額為2000元。事務的隔離性是多個用戶並發訪問數據庫時,數據庫為每一個用戶開啟的事務,不能被其他事務的操作數據所干擾,多個並發事務之間要相互隔離。持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來即使數據庫發生故障也不應該對其有任何影響。
2. 零配置 – 無需安裝和管理配置
3.儲存在單一磁盤文件中的一個完整的數據庫
4.數據庫文件可以在不同字節順序的機器間自由的共享
5.支持數據庫大小至2TB
6. 足夠小, 大致13萬行C代碼, 4.43M
7. 比一些流行的數據庫在大部分普通數據庫操作要快
8. 簡單, 輕松的API
9. 包含TCL綁定, 同時通過Wrapper支持其他語言的綁定
10. 良好注釋的源代碼, 並且有著90%以上的測試覆蓋率
11. 獨立,沒有額外依賴
12. 源碼完全的開源, 你可以用於任何用途, 包括出售它
13. 支持多種開發語言,C, PHP, Perl, Java, C#,Python, Ruby
SQLite在iOS中的基本使用
在iOS開發中可以用一些SQLite數據庫管理工具,例如SQLiteManager。
接下來就通過代碼來講述iOS中如何使用sqlite
sqlite.h文件的引入
首先是打開和關閉數據庫,打開和創建數據庫都是sqlite3_open函數,如果filename已經創建那就是打開。
NSString *filename;//數據庫文件路徑 sqlite3 *database; //sqlite3數據庫句柄的指針 //打開數據庫 - (int) open{ int rc=sqlite3_open([filename UTF8String], &database); if (rc) { sqlite3_close(database); NSLog(@"open database failed"); } return rc; } //關閉數據庫 - (void) close{ if (database!=NULL) { sqlite3_close(database); } } 接下來插入、刪除、更新都是用sqlite3_exec函數,記住執行語句,必須要先打開數據庫,完成之後需要關閉數據庫。 //執行 insert,update,delete 等非查詢SQL語句 - (int)executeNonQuery:(NSString *)sql error:(NSError **)error { int rc; char *errmsg; rc = [self open]; if (rc) { //錯誤處理 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; }
上面函數中sqlite3_free就是釋放存放錯誤信息的內存空間。查詢操作會略顯復雜,同樣需要有開關數據庫的操作,不過有一個准備結果集和最後釋放結果集的操作,分別是sqlite3_prepare_v2和sqlite3_finalize,sqlite3_stmt就是結果集,下面就是具體操作。
[self open]; // 查 strsql = "select * from users"; // SQLITE_API int sqlite3_prepare_v2( // sqlite3 *db, /* Database handle */ // const char *zSql, /* SQL statement*/ // int nByte, /* 結果集的最大長度。*/ // sqlite3_stmt **ppStmt, /* OUT: 結果集 */ // const char **pzTail /* OUT:指向結果集沒有用到的內存部分的指針。 */ // ); sqlite3_stmt* rc;//陳述式句柄 if (sqlite3_prepare_v2(db, strsql, -1, &rc, NULL)!=SQLITE_OK) { } // sqlite3_step講結果集數據指針指向下一個元素。 // 這個函數的返回值如果是SQLITE_ROW就表示我們的結果集裡面有數據。 // 否則我們的結果集就是空的。 while (sqlite3_step(rc)==SQLITE_ROW) { // sqlite3_column系列函數。一般有兩個輸入參數。第一個是結果集指針,第二是數據所在列的序號。 // 比如我們現在用的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)); } // 查完後一定要釋放結果集。 sqlite3_finalize(rc); [self close];
數據庫加密
免費版的SQLite有一個致命缺點:不支持加密。這就導致存儲在SQLite中的數據可以被任何人用任何文本編輯器查看到。
對數據庫加密的思路有兩種:
1. 將內容加密後再寫入數據庫
這種方式使用簡單,在入庫/出庫只需要將字段做對應的加解密操作即可,一定程度上解決了將數據赤裸裸暴露的問題。
不過這種方式並不是徹底的加密,因為數據庫的表結構等信息還是能被查看到。另外寫入數據庫的內容加密後,搜索也是個問題。
2. 對數據庫文件加密
將整個數據庫整個文件加密,這種方式基本上能解決數據庫的信息安全問題。目前已有的SQLite加密基本都是通過這種方式實現的。這裡就介紹一個開源的加密工具SQLCipher,安裝方法可以參照官網文檔,https://www.zetetic.net/sqlcipher/ios-tutorial/,SQLCipher使用256-bit AES加密,由於其基於免費版的SQLite,主要的加密接口和SQLite是相同的,但也增加了一些自己的接口。
其實SQLite的兩個加密函數使用起來非常的簡單,下面分情況說明:
1 給一個未加密的數據庫添加密碼:如果想要添加密碼,則可以在打開數據庫文件之後,關閉數據庫文件之前的任何時刻調用sqlite3_key函數即可,該函數有三個參數,其中第一個參數為數據庫對象,第二個參數是要設定的密碼,第三個是密碼的長度。例如:sqlite3_key(db,”1q2w3e4r”,8); //給數據庫設定密碼1q2w3e4r
2 讀取一個加密數據庫中的數據:完成這個任務依然十分簡單,你只需要在打開數據庫之後,再次調用一下sqlite3_key函數即可,例如,數據庫密碼是123456時,你只需要在代碼中加入sqlite3_key(db,”123456″,6);
3更改數據庫密碼:首先你需要使用當前的密碼正確的打開數據庫,之後你可以調用sqlite3_rekey(db,”112233″,6) 來更改數據庫密碼。
4 刪除密碼:也就是把數據庫恢復到明文狀態。這時你仍然只需要調用sqlite3_rekey函數,並且把該函數的第二個參數置為NULL或者””,或者把第三個參數設為0。
事務操作
那麼問題又來了,如果iOS的sqlite同時插入或者查詢10000條數據,你該怎麼辦?
這裡有三步要做,第一,減少開關數據庫操作,插入10000條數據,不能開關10000次數據庫,只能進行一次開關;
第二,就是不能放在主線程;
第三,最重要的一點就是加入事務操作。
事務(Transaction)是訪問並可能更新數據庫中各種數據項的一個程序執行單元(unit)。在sqlite插入數據的時候默認一條語句就是一個事務,有多少條數據就有多少次磁盤操作。所以10000次磁盤操作可能幾分鐘都做不完,這個時候需要把10000條語句都封裝成一個事務。
下面就是開始事務和提交事務的代碼了
-(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;}
接下來就把三個操作合並
-(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; }
有關iOS中SQLite使用教程小編就給大家介紹這麼多,希望對大家有所幫助!