在IOS開發中經常會需要存儲數據,對於比較少量的數據可以采取文件的形式存儲,比如使用plist文件、歸檔等,但是對於大量的數據,就需要使用數據庫,在IOS開發中數據庫存儲可以直接通過SQL訪問數據庫,也可以通過ORM進行對象關系的映射,當然也可以選擇使用第三方框架實現對數據庫的操作。在這里,主要來講解一下第一種方式,SQLite。
SQLite
數據庫有很多,分為重量級和輕量級兩類,移動設備的內存比較小,因此需要選擇輕量級的數據庫。在移動設備上應用程序開發中使用數據庫,比較主流的是SQLite。SQLite支持跨平台,雖然是輕量級的數據庫,但是它的功能很強大,其功能不亞於很多大型的關系數據庫。
SQLite基於C語言開發的輕型數據庫,因此需要使用C語言語法進行數據庫操作、訪問,不能直接使用OC語言訪問數據庫。此外,SQLite中采用的是動態數據類型,即使創建時定義了一種類型,在實際操作時也可以存儲其他類型,但是推薦建庫時使用合適的類型,特別是應用需要考慮跨平台的情況時。
SQLite可以直接在代碼中使用,但是在開發的過程中,最好安裝一個可以直接打開數據庫的工具,來驗證對數據庫的操作是否正確,方便程序調試。大家可以去SQLite官方網站下載Mac OSX系統下的命令行工具,也可以使用類似於SQLiteManager、MesaSQLite等工具。
數據庫的使用,主要包括對數據庫的打開關閉、創建表格、對數據庫中的數據進行增刪改查以及更新等操作,實際上也就是通常所講的SQL語句,SQLite中的SQL語法並沒有太大的差別,因此這里對於SQL語句的內容不過多贅述,大家可以參考其他SQL相關的內容,在這里,我們來詳細講解一下在IOS開發中的SQLite的使用。
SQLite使用步驟:
1. 在項目中導入libsqlite3.0.dylib框架
2. 獲取數據庫的路徑,一般是獲得獲得沙盒中Document文件夾路徑,然后拼接得到數據庫路徑
3. 創建或者打開數據庫,需要注意的是,在打開的時候需要使用C語言,因此需要先將路徑轉為C的字符串,然后通過sqlite3_open()打開數據庫,如果文件存在則直接打開,否則創建並打開。根據sqlite3_open()返回值來判斷是否正確成功打開,如果成功打開,就可以使用得到的sqlite3類型的對象,來對數據庫進行其他操作。
4. 執行寫好的SQL語句,對數據庫進行操作,執行SQL語句有兩種,一種是無返回值語句,比如創建、增加、刪除等,一種是有返回值的語句,比如查詢。
(1). 對於無返回值的語句(如增加、刪除、修改等)直接通過sqlite3_exec()函數執行,因此可以封裝一個方法,用於除查詢以外的操作
(2). 對於有返回值的語句則首先通過sqlite3_prepare_v2()進行sql語句評估(語法檢測),然后通過sqlite3_step()依次取出查詢結果的每一行數據,對於每行數據都可以通過對應的sqlite3_column_類型()方法獲得對應列的數據,如此反復循環直到遍歷完成。當然,最后需要釋放句柄。
5. SQLite操作是持久連接,在整個操作過程中無需管理數據庫連接,如果使用完畢,可以選擇通過sqlite3_close()手動關閉數據庫
SQLite使用代碼
導入框架,如圖所示
// ViewController.m // JRSQLite查詢3 // // Created by jerehedu on 15/6/16. // Copyright (c) 2015年 jerehedu. All rights reserved. // #import "ViewController.h" #import <sqlite3.h> @interface ViewController () { sqlite3 *db; //聲明數據庫對象 } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 獲得數據庫路徑 // 獲得沙盒中Document文件夾路徑 NSString *dbPath = [self getUserDocumentPath]; // 拼接得到數據庫路徑 NSString *sqlitePath = [dbPath stringByAppendingPathComponent:@"test.sqlite"]; // 創建或打開數據庫 const char *p = [sqlitePath UTF8String]; int res = sqlite3_open(p, &db); if (res==SQLITE_OK) { NSLog(@"db open"); //<一>創建表格 NSString *sql = @"create table if not exists temps (t_id integer primary key autoincrement,t_name varchar(20) )"; if ([self execNoQueryWithSQL:sql]) { NSLog(@"table temps is created"); } //<二>插入數據 NSString *insert_Sql = @"insert into temps (t_name) values ('pear')"; if ([self execNoQueryWithSQL:insert_Sql]) { NSLog(@"table insert "); } //<三>刪除數據 NSString *delete_sql = @"delete from temps where t_id=2"; if ([self execNoQueryWithSQL:delete_sql]) { NSLog(@"table delete "); } //<四>修改數據 NSString *update_sql = @"update temps set t_name='ios' where t_id=1"; if ([self execNoQueryWithSQL:update_sql]) { NSLog(@"table update "); } //<五>查詢簡單的數據1 NSString *select_sql1 = @"select * from temps where t_id=1"; sqlite3_stmt *stmt1 = [self execQueryWithSQL:select_sql1]; while (sqlite3_step(stmt1) == SQLITE_ROW) { //按照當前列的類型選數據,列數從0開始 int t_id = sqlite3_column_int(stmt1, 0); const unsigned char *t_name = sqlite3_column_text(stmt1, 1); NSString *name = [NSString stringWithUTF8String:(char*)t_name]; NSLog(@"%i %@",t_id,name); } //釋放stmt statement sqlite3_finalize(stmt1); //<五>查詢數據2 參數化的sql語句 查找id>2 並且名字以p開頭的 //用?占位 int seachId2 = 2; NSString *seach_name = @"p%"; NSString *seach_sql = @"select * from temps where t_id>? and t_name like ?"; sqlite3_stmt *stmt6 = [self execQueryWithSQL:seach_sql andWithParams:@[[NSNumber numberWithInt:seachId2],seach_name]]; //准備執行(相當於點擊run query),執行的時候是一行一行的執行 while (sqlite3_step(stmt6) == SQLITE_ROW) { //按照當前列的類型選數據,列數從0開始 int t_id = sqlite3_column_int(stmt6, 0); const unsigned char *t_name = sqlite3_column_text(stmt6, 1); NSString *name = [NSString stringWithUTF8String:(char*)t_name]; NSLog(@"..>>>>>>...%i %@",t_id,name); } sqlite3_finalize(stmt6); } // 關閉數據庫 sqlite3_close(db); } #pragma mark - 獲得沙盒sandbox里面document文件夾路徑 - (NSString *)getUserDocumentPath { NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentPath = [path firstObject]; return documentPath; } #pragma mark - 執行除查找以外的數據庫操作方法 -(BOOL)execNoQueryWithSQL:(NSString*)sql { /* 執行 參數1:sqlite3 對象 參數2:c形式的 sql語句 參數3:回調函數 參數4:回調函數的參數 參數5:錯誤信息(可以char類型指針接受錯誤信息,用來查錯使用) */ if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, NULL) == SQLITE_OK) { return YES; } return NO; } #pragma mark 返回查詢結果集(簡單無參) -(sqlite3_stmt *)execQueryWithSQL:(NSString*)sql { //執行sql語句之后,返回的結果語句 sqlite3_stmt *stmt; /* 准備執行查詢的sql語句 (相當於把查詢語句寫好) 參數3:sql語句長度,通常用-1表示(系統會自動計算),也可以用strlength函數計算 參數4:sql_stmt對象 (執行的對象) 參數5:未執行的sql語句 */ int pre_res = sqlite3_prepare_v2(db, [sql UTF8String], -1, &stmt, NULL); //如果准備成功 if (pre_res == SQLITE_OK) { return stmt; } return NULL; } #pragma mark - 返回查詢結果集(有參數的) -(sqlite3_stmt *)execQueryWithSQL:(NSString *)sql andWithParams:(NSArray *)params { sqlite3_stmt *stmt; int pre_res = sqlite3_prepare_v2(db, [sql UTF8String], -1, &stmt, NULL); if (pre_res == SQLITE_OK) { //有參數,循環綁定參數 if (params!=nil) { for (int i=0; i<params.count; i++) { id obj = params[i]; //綁定的數據類型可能為NSString或者NSNumber,或者數據為空,分別判斷 if (obj==nil) { //如果數據為nil sqlite3_bind_null(stmt, i+1); } else if ([obj respondsToSelector:@selector(objCType)]) { //當前的綁定的數據類型位NSNumber //NSNumber判斷包裝的是int?longInt?shortInt?float?double? /* strstr(參數1,參數2) (strstr() c中函數搜索一個字符串在另一個字符串中的第一次出現,則該函數返回第一次匹配的字符串的地址,找不到返回NULL) 判斷參數1中的字符在參數2的字符串char*中出現的索引 [obj objCType] 如果obj是int返回字符串i */ if (strstr("ilsILS", [obj objCType])) { /* 綁定參數 如果有where 參數1:sqlite_stmt對象 (statement結果集) 參數2:占位符索引 從1開始 參數3:替代占位符的真實參數 */ sqlite3_bind_int(stmt, i+1, [obj intValue]); } else if (strstr("fdFD", [obj objCType])) { sqlite3_bind_double(stmt, i+1, [obj doubleValue]); } else { stmt = nil; } } else if ([obj respondsToSelector:@selector(UTF8String)]) { //當前的綁定的數據類型位NSString 判斷是否有UTF8String方法 //用bind替換占位符 索引從1開始 sqlite3_bind_text(stmt, i+1, [obj UTF8String], -1, NULL); } else { stmt = nil; } } return stmt; } } return NULL; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } @end
疑問咨詢或技術交流,請加入官方QQ群: (452379712)
出處: http://www.cnblogs.com/jerehedu/
本文版權歸煙台傑瑞教育科技有限公司和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。