為什么要搞一搞SQLite的C語言接口規范呢? 因為在做iOS開發中難免會遇到操作數據庫的情況,你可以使用第三方的FMDB等,或者使用CoreData。但我們還是有必要去搞清楚如何去使用SQLite的C語言接口來操作SQLite數據庫的。從今天開始就給大家結合實例詳細的搞一搞SQLite的C語言接口。關於CoreData的東西請看之前的博客《IOS開發之表視圖愛上CoreData》。
如果英文好的小伙伴呢,你可以不聽我啰嗦,直接官網走起:http://www.sqlite.org 上面的東西是應有盡有,你可以下載資源如SQLite的Shell, 上面還有好多的學習資源。不過前提是英文不能太Low呢。之前看過幾本iOS開發的書籍,也包括某某出版社出版的《精通iOS開發》,雖然網上評價不錯,但看書的時候總是不來感。大部分書上介紹的SQLite, 講的太淺,只是羅列代碼,接口參數是什么意思,為什么這么寫都沒講。看書看的不爽了,就到官網上找找安慰吧,果不其然,眼前一亮。就寫幾篇博客好好的總結一下。
一、准備SQLite測試工程和所需工具
1. 准備一個已經引入動態鏈接庫libsqlite3.0.dylib的iOS單視圖工程(當然,看你心情,你也可以創建一個控制台工程,這不是重點)。
2. 准備一個SQLite可視化的管理工具,我用的是SQLiteManager, 當然你可以選擇你用着順手的管理工具(自行百度吧)。當然如果你是初學者,並想“自殘”一下話,可以從官網上Download一個叫做sqlite-shell的東西,用純命令行去管理你的SQLite數據庫。其實如果習慣了,用純命令還是用着比較爽的,畢竟可以用來裝13不是么! SQLite官網上有詳細的Shell操作命令:如何去創建數據庫,如何創建表等一系列的操作,今天不做贅述。(如果你之前搞過MySQL, Oracle等,應該對命令行操作數據庫再熟悉不過了)。
3. 你可以通過SQLiteManager來創建一個數據庫插入一些測試數據,以備在我們的測試工程中進行使用。或者你可以懶一些,直接從網上Download一個現成的SQLite數據庫進行操作使用(我下載了一個叫做Cars.sqlite文件來進行測試,數據庫的表結構及數據如下所示)。

二、打開你的數據庫
1.把准備好的測試SQLite數據庫引入到我們的測試工程中。
2.通過NSBundle加載我們的數據庫資源
//獲取Sqllite文件的路徑 NSString *sqlPath = [[NSBundle mainBundle] pathForResource:@"Cars" ofType:@"sqlite"];
3.因為是C語言接口,參數所用的字符串都是C語言中的字符串,所以呢得把字符串轉成C語言中的字符串吧(也就是C語言中char類型的指針)
//把路徑轉成C字符串 const char * filePath = [sqlPath UTF8String];
4.你需要定義一個sqlite3結構體類型的指針變量,打開數據庫后可以獲取這個sqlite3結構體指針的值,並賦值給之前對應的指針變量,然后就可以通過該sqlite3結構體指針變量來操作數據庫。下面定義了一個sqlite3結構體類型的指針變量,然后把該指針變量的地址傳給sqlite3_open()函數,函數參數傳入的引用,在C語言中就可以得到數據庫操作指針。為了便於理解,可以把sqlite3結構體當做一個類,而sqlite3結構體的指針可以看做是類的對象。
sqlite3 * database; //打開數據庫 int result = sqlite3_open(filePath, &database);
通過上述步驟就可以獲取到操作數據庫的結構體指針,sqlite3_open()函數,第一個參數就是C字符串格式的數據庫文件的路徑,第二個參數就是結構體指針的地址,用於獲取操作數據庫的句柄。該函數有一個int類型的返回值(0-101),這些返回值對應着不同的鏈接狀態。0代表着成功,其余見下圖:
if (result == SQLITE_OK) { NSLog(@"連接成功"); } else { NSString *error = [NSString stringWithFormat:@"錯誤結果代碼:%d", result]; NSLog(@"%@", error); }

sqlite3_open()就是一個構造函數, 另外還有sqlite3_open16()和sqlite3_open_v2(), 他們的功能都是打開一個新的數據庫的連接,所需參數如下所示。這些構造函數可以通過數據庫文件名稱參數來連接一個數據庫。如果文件名參數是UTF-8編碼格式的, 可以調用sqlite3_open()和sqlite3_open_v2(), 那么如果文件參數是 UTF-16編碼的話就調用構造函數sqlite3_open16()。第二個參數就是返回的數據庫操作句柄的指針地址。
由下方的圖可以看出sqlite3_open_v2()比sqlite3_open()多了兩個參數,一個是int flags, 一個是const char *zVfs。 sqlite3_open_v2()的用法和sqlite3_open()類似,可以說前者是后者的加強版。sqlite3_open()是以前的舊方法,而sqlite3_open_v2()是后來改進的方法。

參數flag,不同的值代表着打開數據庫后可以獲取的不同操作,類似於數據庫的操作權限,下方是flag的值代表的操作權限。
SQLITE_OPEN_READONLY 數據庫是只讀模式打開。如果數據庫不存在,則返回一個錯誤。
SQLITE_OPEN_READWRITE 數據庫以讀寫的模式打開, 如果文件被操作系統設置為保護模式,那么就為只讀模式。在這兩種情況下的數據庫必須已經存在,否則會返回一個錯誤。
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE 數據庫以讀寫的模式打開, 如果數據庫不存在,就創建一個。使用sqlite3_open()和sqlite3_open16()連接數據庫時,默認的就是這種行為。
如果sqlite3_open_v2()的第三個參數不包含上述三種結合中的一個的話,那么數據庫的連接權限是未定義的。也就是說數據庫不知道是讀還是寫,還是創建,所以操作數據庫就沒有意義了,所以上面必須選擇一個參與“與”運算。
SQLITE_OPEN_NOMUTEX 只要單線模式下沒有設置編譯的起始時間,就會在多線程模式下進行數據庫的連接。
SQLITE_OPEN_FULLMUTEX 在序列化的線程模式(在此模式中,SQLite能無約束地在多線程中安全使用)打開數據庫連接,除非在編譯時或者單線程之前選擇起始時間。
SQLITE_OPEN_SHAREDCACHE 可以使數據庫連接適當的使用共享緩存模式,無論是否使用sqlite3_enable_shared_cache()啟用共享緩存。
SQLITE_OPEN_PRIVATECACHE 導致數據庫連接不使用共享緩存模式,即使共享緩存模型可用。

sqlite3_open_v2()第四個參數是sqlite3_vfs對象的名稱,它定義了操作系統接口應該使用新的數據庫連接。如果第四個參數是一個nil的話,那么就會使用默認sqlite3_vfs對象。下方是結構體sqlite3_vfs的具體內容:

vfs: sqlite3_vfs對象的實例定義了一個SQLite核心和底層操作系統間的接口。“vfs”對象的名稱代表“虛擬文件系統”。關於VFS的詳解內容在這里:https://www.sqlite.org/vfs.html 有興趣的小伙伴可以好好的搞一下。如果以后有時間的話在好好的介紹一下VFS。今天就不做過多的贅述了。第四個參數傳入nil就會使用默認的sqlite3_vfs默認對象。
關於VFS和sqlite3_vfs結構體的東西,如果以后有時間,在單獨拿出來搞搞。了解VFS的結構和模式還是很有必要的。ok~今天打開並連接數據庫,關於如何去通過接口去操作數據庫就留在以后的博客中介紹吧。
用到的數據庫和sqliteAPI代碼GitHub分享地址:https://github.com/lizelu/SQLiteResource
在博客的最后呢,給出簡單封裝的打開數據庫的方法:
1 /******************************* 2 *功能:打開數據庫 3 *參數:databaseName -- 數據庫名稱 4 *返回:數據庫對象(sqlite3對象) 5 *******************************/ 6 + (sqlite3 *) openDatabaseWithName: (NSString *)databaseName{ 7 8 //獲取Sqllite文件的路徑 9 NSString *sqlPath = [[NSBundle mainBundle] pathForResource:databaseName ofType:@"sqlite"]; 10 11 //把路徑轉成C字符串 12 const char * filePath = [sqlPath UTF8String]; 13 14 sqlite3 * database; 15 16 //打開數據庫 17 int result = sqlite3_open(filePath, &database); 18 19 if (result == SQLITE_OK) { 20 return database; 21 } 22 23 return nil; 24 25 }
