IOS 數據存儲之 SQLite詳解

  在IOS開發中常常會須要存儲數據,對於比較少許的數據能夠採起文件的形式存儲,好比使用plist文件、歸檔等,可是對於大量的數據,就須要使用數據庫,在IOS開發中數據庫存儲能夠直接經過SQL訪問數據庫,也能夠經過ORM進行對象關係的映射,固然也能夠選擇使用第三方框架實現對數據庫的操做。在這裏,主要來說解一下第一種方式,SQLite。html

SQLiteios

  數據庫有不少,分爲重量級和輕量級兩類,移動設備的內存比較小,所以須要選擇輕量級的數據庫。在移動設備上應用程序開發中使用數據庫,比較主流的是SQLite。SQLite支持跨平臺,雖然是輕量級的數據庫,可是它的功能很強大,其功能不亞於不少大型的關係數據庫。web

  SQLite基於C語言開發的輕型數據庫,所以須要使用C語言語法進行數據庫操做、訪問,不能直接使用OC語言訪問數據庫。此外,SQLite中採用的是動態數據類型,即便建立時定義了一種類型,在實際操做時也能夠存儲其餘類型,可是推薦建庫時使用合適的類型,特別是應用須要考慮跨平臺的狀況時。sql

  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類型的對象,來對數據庫進行其餘操做。spa

  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羣:JRedu技術交流 (452379712)

 

做者: 傑瑞教育
出處: http://www.cnblogs.com/jerehedu/ 
本文版權歸煙臺傑瑞教育科技有限公司和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。
相關文章
相關標籤/搜索