SQLite

SQLite 裏最常用的就是 sqlite3* 類型,從數據庫打開開始,sqlite就要爲這個類型準備好內存,直到數據庫關閉,整個過程都要用到這個類型,從數據庫打開開始,這個類型的變量就代表了你要操作的數據庫。

sqlite3 *database;
不要忘記在工程中加入庫文件libsqlite3.dylib和頭文件#import<sqlite3.h>

1.打開數據庫

int sqlite3_open(const char *filename, sqlite3 **ppDb);

第1個參數是數據庫文件地址,比如,"~/Hunk/MyFiles/database.sqlite3",iOS中常用的是放在Sandbox下的路徑,比如放在Documents文件夾下,此文件名不需要一定存在,如果不存在,SQLite會自動創建它;如果存在,就直接打開數據庫文件.因爲此處是const char * 的參數在iOS中需要通過UTF8String做一個簡單的轉換
- (NSString *)dataFilePath
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    
    NSString *documentsDirectory = [paths objectAtIndex:0];
    
    return [documentsDirectory stringByAppendingPathComponent:@"database.sqlite3"];
}

第2個參數是sqlite**,傳入sqlite3*的指針即可。

函數返回值表示操作是否正確,如果是SQLITE_OK表示操作正常。

int result = sqlite3_open([[self dataFilePath] UTF8String], database);


2.關閉數據庫

int sqlite3_colse(sqlite3 **ppDb);
如果數據庫打開成功,那麼一定要關閉數據庫。


3.SQL語句執行操作

int sqlite3_exec(sqlite*, const char * sql, int(*callback), void*, char* errmsg);
第1個參數就是sqlite3*;

第2個參數就是sql語句,如:const char *sql = "select * from my_table";

第3個參數是一個回調函數,當這條語句執行完之後就會去調用你提供的這個函數;

第4個參數是你所提供的指針,可以傳遞任何一個指針參數到這裏,這個參數最終會傳到回調函數裏面,如果不需要傳遞函數指針給回調函數,填NULL即可。

第5個參數是錯誤信息,是指針的指針。執行失敗時可以輸出這個指針所指的信息。

printf(“%s\n”,errmsg)

通常, 回調函數 和它後面的 void * 這兩個位置都可以填 NULL。填 NULL 表示你不需要回調。比如你做 insert 操作,做 delete 操作,就沒有必要使用回調。而當你做 select 時,就要使用回調,因爲 sqlite3 把數據查出來,得通過回調告訴你查出了什麼數據,特殊情況特殊對待。

sqlite3_exec(database, "select * from my_table", callbackInfo, NULL, &errorMsg);

sqlite3_exec函數的回調函數

int (*callback)(void*,int,char**,char**)

回調函數必須定義成上面函數的形式。


第1個參數你可以傳入一些特殊的指針(比如類指針、結構指針),然後在這裏面強制轉換成對應的類型(這裏面是void*類型,必須強制轉換成你的類型纔可用)。然後操作這些數據。

第2個參數n_column是這一條記錄有多少個字段(這條記錄有多少列)

第3個參數char ** column_value是個關鍵值,查出來的數據都保存在這裏,它實際上是個1維數組(不要以爲是2維數組),每一個元素都是一個char *值,是一個字段內容(用字符串來表示,以\0 結尾)

第4個參數char ** column_name column_value是對應的,表示這個字段的字段名稱。

int callbackInfo(void *para, int n_column, char **column_value, char **column_name)
{
    // 取值成功
    for (int i = 0; i < strlen(*column_value); i++) 
    {
        for(int j = 0; j < n_column; j++)
        {
            //                    NSLog(@"字段名:%@---字段值:%@\n", result[j], result[index]);
            printf( "字段名:%s > 字段值:%s\n", column_name[j], column_value[j]);
        }
    }
    return 0;
}



4.數據庫操作

關鍵在於sql語句。

創建表:    create table my_table(id integer primary key autoincrement, name varchar(32), description text)

插入數據:insert into my_table(name, description) values('Hunk', '男');


5.不使用回調函數查詢數據庫

int sqlite3_get_table(
  sqlite3 *db,          /* An open database */
  const char *zSql,     /* SQL to be evaluated */
  char ***pazResult,    /* Results of the query */
  int *pnRow,           /* Number of result rows written here */
  int *pnColumn,        /* Number of result columns written here */
  char **pzErrmsg       /* Error msg written here */
);

第1,2個參數不必多說;
第3個參數是查詢結果,它依然一維數組(不要以爲是二維數組,更不要以爲是三維數組 ),它內存佈局是:第一行是字段名稱,後面是緊接着是每個字段的值;
第4個參數是查詢出多少行,即多少條紀錄;
第5個參數是查詢出多少列,即多少個字段;
第6個參數,錯誤信息。
if(sqlite3_get_table(database, "select * from my_table", &result, &nRow, &nColumn, &errorMsg) == SQLITE_OK)
            {
                // 取值成功
                for(int i = 0; i < nRow; i++)
                {
                    for(int j = 0; j < nColumn; j++)
                    {
                        printf( "字段名:%s > 字段值:%s\n", result[j], result [index]);
                        ++index;
                    }
                }
                sqlite3_free_table(result);
            }

無論數據庫查詢是否成功,都釋放 char**查詢結果,
sqlite3_free_table(result);
  

6.寫入二進制數據

要寫入二進制數據,那麼這個表的字段類型就應是blob類型。

sqlite操作二進制數據需要用一個輔助的數據類型:sqlite3_stmt *。這個數據類型記錄了一個“sql 語句”。爲什麼我把 “sql 語句” 用雙引號引起來?因爲你可以把sqlite3_stmt *所表示的內容看成是sql語句,但是實際上它不是我們所熟知的sql語句。它是一個已經把sql語句解析了的、用sqlite自己標記記錄的內部數據結構 。正因爲這個結構已經被解析了 ,所以你可以往這個語句裏插入二進制數據。當然,把二進制數據插到 sqlite3_stmt 結構裏可不能直接std::string 那樣用+ 號。必須用 sqlite 提供的函數來插入。 


通過sqlite_exec創建一張表

const char *sql = "create table my_table(id integer primary key autoincrement, content blob)";

聲明statement

sqlite3_stmt *statement;

通過sqlite_prepare把sql語句解析到statement裏

sqlite3_prepare(database, "insert into my_table(id, content, description) values(13, ?, ?)", -1, statement, 0);

第3個參數寫的是-1,這個參數意思是前面sql語句的長度。如果小於0,sqlite會自動計算它的長度(把 sql 語句當成以\0 結尾的字符串);

第4個參數是 sqlite3_stmt 的指針的指針。解析以後的sql語句就放在這個結構裏;

如果這個函數執行成功(返回值是SQLITE_OK 且statement 不爲 NULL ),那麼下面就可以開始插入二進制數據

int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));

sqlite3_bind_blob(statement, 1, &pdata, 100, NULL)

sqlite3_bind_blob(statement, 2, &pdata, 200, NULL)

第1個參數就是statement;

第2個參數 ?(前面prepare語句裏有一個?(問號))的索引,假如有多個?號怎麼插入?方法就是改變 bind_blob 函數第 個參數。這個參數我寫 1,表示這裏插入的值要替換 statement 的第一個 ?號(這裏的索引從 開始計數,而非從 開始)。如果你有多個 ?號,就寫多個 bind_blob 語句,並改變它們的第 個參數就替換到不同的?號。如果有?號沒有替換,sqlite 爲它取值 null;

第3個參數是二進制數據的其實指針;

第4個參數是二進制數據的長度,以字節爲單位;

5個參數是個析夠回調函數,告訴sqlite當把數據處理完後調用此函數來析夠你的數據。

 

bind 完了之後,二進制數據就進入了你的“sql 語句”裏了。你現在可以把它保存到數據庫裏 :

int result = sqlite3_step(statement);
通過這個語句,statement 表示的sql語句就被寫到了數據庫裏。

 

最後,要把sqlite3_stmt結構給釋放:(把剛纔分配的內容析構掉)

sqlite3_finalize(statement);

7.讀出二進制數據

sqlite3_stmt *statement;
        if(SQLITE_OK == sqlite3_prepare(database, "select * from my_table", -1, &statement, NULL))
        {
            while(SQLITE_ROW == sqlite3_step(statement)) // SQLITE_ROW 100) 
            {
                int nID = sqlite3_column_int(statement, 0);
                
                const void *content = sqlite3_column_blob(statement, 1);
                int length = sqlite3_column_bytes(statement, 1);
                
                NSLog(@"%d---%d", nID, length);
            }   
            
            sqlite3_finalize(statement);
        }
int result = sqlite3_step(statement);這一句的返回值是SQLITE_ROW時表示成功(不是SQLITE_OK).

循環執行 sqlite3_step 函數,一次step查詢出一條記錄。直到返回值不爲SQLITE_ROW,時表示查詢結束。


int sqlite3_column_int(sqlite3_stmt*,int iCol);

第2個參數表示獲取第幾個字段的內容,因爲我的id是第一個字段,從0開始計算,所以填0


獲取content的值,content的值是二進制數據,那麼需要獲取到它的指針和長度

const void *content = sqlite3_column_blob(statement, 1);
int length = sqlite3_column_bytes(statement, 1);
析構statement
sqlite3_finalize(statement);    

8.重複使用 sqlite3_stmt結構

如果你需要重複使用 sqlite3_prepare 解析好的 sqlite3_stmt 結構,需要用函數: sqlite3_reset。
result = sqlite3_reset(statement);
這樣, statement 結構又成爲 sqlite3_prepare 完成時的狀態,你可以重新爲它 bind 內容。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章