SQLite是一款輕量級的數據庫,是遵照ACID的關聯式數據庫管理系統,它的設計目標是嵌入式的,並且目前已經在不少嵌入式產品中使用了它,它佔用資源很是的低,在嵌入式設備中,可能只須要幾百K的內存就夠了。它可以支持Windows/Linux/Unix等等主流的操做系統,同時可以跟不少程序語言相結合,好比 Tcl、C#、PHP、Java等,還有ODBC接口,固然還有咱們使用的Obj-C。用這種方法保存的數據既能夠在客戶端存儲大量數據,同時可以利用SQL語句靈活地查詢、插入、更新或者刪除數據。sql
本人在開發過程當中發現關於iOS中SQLite的編程文章實在太少了,大多數都是涉及都一些簡單的操做。所以,下面寫到的操做我會在簡單的SQLite操做基礎上(其中包括打開/關閉數據庫、構造表、插入、更新或者刪除數據操做),再增長兩項數據庫操做中比較經常使用的功能實踐,分別實現帶參數SQL語句的執行以及數據庫的事物啓動、提交和回滾。廢話很少說,直接進入主題吧。數據庫
在iOS中使用SQLite咱們須要加入libsqlite3.dylib的庫,並在引入SQLite的頭文件。以下:編程
#import <sqlite3.h>
導入庫和頭文件以後,接下來的操做就是打開一個數據庫。這時候須要調用sqlite3_open這個函數來對打開一個數據庫文件。此函數聲明以下:安全
int sqlite3_open( const char *filename, /* Database filename (UTF-8) */ sqlite3 **ppDb /* OUT: SQLite db handle */ );
其中第一個參數就是數據庫所存放的路徑,若是路徑下沒有數據庫文件則系統會在此路徑下建立一個數據庫。至於第二個參數則是數據庫的句柄引用,但此函數調用成功後此句柄將會保存打開數據庫的句柄,此句柄在日後的數據庫操做中須要用到。所以,可以下方式調用:函數
NSString *dbPath=[NSString stringWithFormat:@」%@/Documents/demo.db」,NSHomeDirectory()]; sqlite3 *dbHandle; if (sqlite3_open([path UTF8String], &dbHandle)==SQLITE_OK) { NSLog(@「打開數據庫成功!」); }
既然有打開數據庫,那麼就確定有關閉數據庫的操做了,咱們要養成良好的習慣,當須要使用數據庫的時候就執行sqlite3_open來打開數據庫,等使用完數據庫後就調用sqlite3_close函數來對數據庫進行關閉。關於sqlite3_close函數聲明以下:lua
int sqlite3_close(sqlite3 *);
關閉時傳入數據庫句柄便可對數據庫進行關閉。調用方式以下:spa
if(sqlite3_close(dbHandle)==SQLITE_OK) NSLog(@「關閉數據庫成功!」);
接下來須要講述的是如何對數據庫進行操做,經常使用的有兩種方式能夠操做數據庫中的數據和調整結構。操作系統
第一種就是sqlite3_exec函數,這種方法通常使用在不返回數據集的狀況,也就是說少用於查詢類的操做,同時筆者也尚發現使用此函數如何配合參數使用。若是使用他來建立表結構、更新、插入或者刪除操做是一種直觀快捷的方法。先來看看此方法的聲明:設計
int sqlite3_exec( sqlite3*, /* An open database */ const char *sql, /* SQL to be evaluated */ int (*callback)(void*,int,char**,char**), /* Callback function */ void *, /* 1st argument to callback */ char **errmsg /* Error msg written here */ );
第一個參數就是咱們打開數據庫的句柄了,第二個參數就是SQL語句,第三個參數爲回調方法的函數指針,一旦指定此參數後,當執行語句爲查詢語句時則在枚舉記錄集時回對調此方法。第四個參數則爲回調的第一個參數引用。關於第三第四個參數還有待研究(若是哪位大蝦知道如何使用,不妨告訴小弟,必定感激涕零)。至於第五個參數就是若是方法執行後存在異常,那麼這個參數保存的就是錯誤的描述信息。指針
第二種就是使用sqlite3_prepare_v2和sqlite3_step兩個函數搭配的進行操做。其中sqlite3_prepare_v2是一個將SQL語句編譯爲sqlite內部一個結構體(sqlite3_stmt).該結構體中包含了將要執行的的SQL語句的信息。而sqlite3_step則是讓轉化後的SQL進行下一步的操做。所以經過這兩個函數能夠很方便的獲取到數據庫中的數據。本人建議使用此方式取得記錄集。下面是這兩個函數的聲明:
int sqlite3_prepare_v2( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */ );
第一個參數就是打開數據庫時的數據庫句柄對象。第二個就是SQL語句。第三個參數是用於指定SQL語句最大的長度,若是此參數爲負數,則根據第二個參數中的第一個終結符爲準做爲一條完整的語句。若是爲非負數,則以第二個參數的第一個終結符(\000或\u0000)或者指定的數字爲準做爲一條完整語句。第四個參數則是調用函數後返回的一個結構體,此結構體包含了相關語句的信息。關於第五個參數是用於指向前一條語句結束位置,一旦指定此參數,則參數指向位置的左邊語句將不進行編譯解析。
sqlite3_step(sqlite3_stmt *);
傳入參數即爲準備語句中的結構體對象。
上面所說的兩種方式我將會在下面舉例進行說明,可是每一個例子不必定兩種方式都實現,若是有這方面興趣的朋友能夠本身嘗試另一種方式實現。
例子一:建立數據表
要想讓數據庫可以存儲數據,那就必須得建立一個數據表才能進行數據操做。而數據表是能夠包含不一樣的數據字段,這些字段能夠指定不一樣的數據類型,存儲不一樣的數據。咱們建表時能夠根據須要進行建立。下面的代碼建立了一個叫作persons的數據表,其包含兩個字段id和name。其SQL語句爲:create table if not exists persons (id integer primary key autoincrement,name);(若是對SQL語句不太熟悉的朋友能夠參考相關方面資料)。那麼代碼以下所示:
char *errorMsg; if (sqlite3_exec(_database, "create table if not exists persons (id integer primary key autoincrement,name);", NULL, NULL, &errorMsg)!=SQLITE_OK) { NSLog(@「操做失敗!」); } sqlite3_free(errorMsg);
上面要注意的一點是,若是你有傳入errorMsg參數,那麼你必須在執行完sqlite3_exec後,執行sqlite3_free函數來釋放errorMsg。不然就會形成內存泄露。
例子二:插入、更新、刪除數據
上面的例子建立了一個數據後,那麼咱們能夠往裏面插入數據,咱們可使用insert語句將數據插入表中:代碼以下所示:
char *errorMsg; if (sqlite3_exec(_database, "insert into persons(name) values(‘張三’);", NULL, NULL, &errorMsg)!=SQLITE_OK) { NSLog(@「操做失敗!」); } sqlite3_free(errorMsg);
上面所作的事情就是把一個張三的數據插入了數據表persons中。上面的實現是很是方便的,可是並不安全,由於咱們的SQL語句中要插入的數據是拼合到SQL語句中的,這樣很容易形成注入問題,所以,咱們可使用下面的方法來實現。
sqlite3_stmt *statement; if (sqlite3_prepare_v2(_database, [@"insert into persons(name) values(?);" UTF8String], -1, &statement, NULL)!=SQLITE_OK) { return; } //綁定參數 const char *text=[@」張三」 cStringUsingEncoding:NSUTF8StringEncoding]; sqlite3_bind_text(statement, index, text, strlen(text), SQLITE_STATIC); if (sqlite3_step(statement)!=SQLITE_DONE) { sqlite3_finalize(statement); return; } sqlite3_finalize(statement);
推薦使用參數進行數據查詢和操做,這樣能夠保證讀寫數據的正確性和提升安全性。對於更新數據和刪除數據的調用方式和插入數據同樣,只是SQL語句的差別,其中更新數據使用Update語法,而刪除表數據則使用Delete語法。
例子三:事務處理
事務在數據庫中是一個重要的概念,使用事務能夠保證數據的統一和完整性。同時也能夠提升效率。拿咱們上面建立的persons表來講,假設我要一次插入20我的的名字纔算是操做成功,那麼,在不使用事務的狀況下,若是插入過程當中出現異常或者在插入過程當中出現一些其餘數據庫操做的話,就頗有可能影響了操做的完整性。因此事務能夠很好地解決這樣的狀況,首先事務是能夠把啓動事務過程當中的全部操做視爲事務的過程。等到全部過程執行完畢後,咱們能夠根據操做是否成功來決定事務是否進行提交或者回滾。提交事務後會一次性把全部數據提交到數據庫,若是回滾了事務就會放棄此次的操做,而對原來表的數據不進行更改。
那麼,如何啓動,提交還有回滾事務呢?SQLite中分別是:BEGIN、COMMIT和ROLLBACK。下面來看一下例子:
@try{ char *errorMsg; if (sqlite3_exec(_database, "BEGIN", NULL, NULL, &errorMsg)==SQLITE_OK) { NSLog(@」啓動事務成功」); sqlite3_free(errorMsg); sqlite3_stmt *statement; if (sqlite3_prepare_v2(_database, [@"insert into persons(name) values(?);" UTF8String], -1, &statement, NULL)==SQLITE_OK) { //綁定參數 const char *text=[@」張三」 cStringUsingEncoding:NSUTF8StringEncoding]; sqlite3_bind_text(statement, index, text, strlen(text), SQLITE_STATIC); if (sqlite3_step(statement)!=SQLITE_DONE) { sqlite3_finalize(statement); } } if (sqlite3_exec(_database, "COMMIT", NULL, NULL, &errorMsg)==SQLITE_OK) { NSLog(@」提交事務成功」); } sqlite3_free(errorMsg); }else{ sqlite3_free(errorMsg); } } @catch(NSException *e){ char *errorMsg; if (sqlite3_exec(_database, "ROLLBACK", NULL, NULL, &errorMsg)==SQLITE_OK) { NSLog(@」回滾事務成功」); } sqlite3_free(errorMsg); } @finally{ }
關於SQLite的操做今天就到這裏告一段落,往後有相關的資料或者經驗再跟你們分享。