一、簡介
SQLite是一個基於文件的輕量級數據庫,但功能還挺強,速度也很快,對於小型數據庫應用開發絕對夠用了。使用起來也非常方便,下面的介紹可以看出來,使用起來真的非常簡單。
二、官方網站
Sqlite的官方網站www.sqlite.org,在該網站可以下載最新的sqlite版本。
三、輔助工具
Sqlite數據庫的管理工具有SQLiteManager、SqliteAdmin等。
SqliteManager只有英文版(需要注冊或者破解方可使用)。其自帶的幫助文檔有SQL語句的詳細介紹,對於不熟悉Sql語句的人來說很方便。而且它的很多操作都有自動的SQL語句提示,對於不常使用數據庫的人來說也很好用。
SqliteAdmin有綠色中文版,功能相對於SqliteManager略少,對於熟悉Sql語句的人,該版本夠用了。
另外說明一下,在我們的程序中以UTF-8方式(大部分人應該都是以這種方式打開的)打開數據庫進行操作時,兩種軟件的表現如下:
如果插入數據庫的數據,漢字是以ANSI字符存儲的話,那么在SqliteAdmin中打開時,會顯示正常漢字,而在SqliteManager中,會顯示為亂碼。
如果插入數據庫的數據,漢字是以UTF-8字符存儲的話,那么在SqliteManager中打開時,會顯示正常漢字,而在SqliteAdmin中,會顯示為亂碼。
很明顯,SqliteManager的表現,要正常一些。SqliteManager更加值得推薦,不過需要安裝和破解。SqliteAdmin是綠色的,但面對ANSI漢字,可能在某些時候力不從心,而且功能沒有SqliteManager強大。
四、C/C++使用前准備
直接將sqlite3.h和sqlite3.c加入自己的C/C++工程中,即可使用sqlite3。
使用VC的用戶特別注意,大多數VC工程,默認都是使用預編譯頭的,需要對sqlite3.c這個文件,去掉預編譯頭,方可編譯通過。去掉的方法是在工程中的文件視圖中,右鍵點擊sqlite3.c這個文件,打開“配置屬性”中的“C/C++”,找到“預編譯頭”,設置為不使用預編譯頭即可。
Sqlite支持UTF-8和UTF-16,不過它居然不支持C/C++程序中最常用的ANSI。因此數據庫路徑中如果包含中文字符的話,需要將路徑轉換成相應的字符格式。
1、以UTF-8方式打開(如果數據庫路徑中包含中文字符,需要進行ANSI到UTF8的轉換)
示例中的路徑是全英文字符,ANSI和UTF8是相同的,因此省去轉化。
//打開數據庫 sqlite3 *db = NULL; int result = sqlite3_open("c:\\abc.db", &db); if (SQLITE_OK != result) { return; } //關閉數據庫 sqlite3_close(db);
2、以UTF-16方式打開
如要以UTF-16方式打開,把打開數據庫的語句改為"sqlite3_open16(L"c:\\abc.db", &db)"即可。
注意:如果以UTF-8方式打開數據庫,那么以后任何數據庫操作,都必須以UTF-8方式進行。UTF-16也同理。
一個比較常見的錯誤是,以UTF-8打開了數據庫,但卻插入了ANSI的漢字。犯下這種錯誤是很不經意的,因為對於英文字符,UTF-8和ANSI是一模一樣的嘛!一個我所知的非常典型的后果就是使用模糊查找語句進行檢索時,可能查詢的結果,並不是你想要的。
執行SQL語句可以調用sqlite3_exec函數,一般來說,如果不需要返回的數據和錯誤信息,執行方式如下:
sqlite3_exec(db, strSQL, 0, 0, 0);
1、創建表
假設創建如下圖所示的數據庫:

其SQL語句為:
CREATE TABLE [MyTable] ([ID] INTEGER PRIMARY KEY NOT NULL,[MyText] TEXT NULL, [MyDate] DATE NOT NULL, [MyTime] TIME NULL,[MyFloat] FLOAT NULL)
下面是插入一條記錄的示例SQL語句。
INSERT INTO MyTable (MyText, MyDate, MyTime, MyFloat) VALUES ('---上班好遠!', '2012-03-23', '9:00:00', 1000)
下面是更新若干條記錄的示例SQL語句。
UPDATE MyTable SET MyText='真的嗎?', MyTime='10:00:00' WHERE ID >=0 AND ID <=20
下面是刪除若干條記錄的示例SQL語句。
DELETE FROM MyTable WHERE ID >=3 AND ID <=5
如果要進行大量的操作,比如要插入10000條數據,如果逐條執行SQL語句,則消耗的時間非常長。采用事務的方式批量處理,可以極大程度提升操作速度(我用1000條記錄實驗了一下,速度提高了500倍以上)。
下面是一個批量插入10000條數據的代碼示例:
//插入條數據(在Begin和Commit之間批量操作,可以大幅度提高效率) result = sqlite3_exec(db, "BEGIN;", 0, 0, 0); for (int i=0; i<10000; i++) { //插入一條數據 result = sqlite3_exec(db, "INSERT INTO MyTable (MyText, MyDate, MyTime, MyFloat) VALUES ('---上班好遠!', '2012-03-23', '9:00:00', 1000);", 0, 0, 0); } result = sqlite3_exec(db, "COMMIT;", 0, 0, 0);
下面是以表單形式獲取數據的示例代碼:
//查詢記錄(返回數據表的方式) char **pazResult; int nRow, nCol; sqlite3_get_table(db, "SELECT * FROM MyTable LIMIT 1000 OFFSET 2000", &pazResult, &nRow, &nCol, 0); //nRow指示出有多少行 //nCol指示出有多少列 //從pazResult中可以解析出所有記錄,記錄以字符串形式返回 //第n列的名稱,存放於pazResult[n] //第n行第m列的數據,存放與paszResult[(n + 1) * nCol + m] //使用完后,務必釋放為記錄分配的內存 sqlite3_free_table(pazResult);
下面以代碼形式示例如何獲得查詢語句返回的記錄。
首先需要定義一個回調函數如下(參數意義待會再說):
int Result(void* pContext, int nCol, char** azValue, char** azName);
然后調用sqlite函數執行查詢語句,在回調函數一欄輸入上面定義的回調函數:
sqlite3_exec(db, "SELECT * FROM MyTable LIMIT 10 OFFSET 20", Result, 0, 0);
執行該SQL語句時,每返回一條記錄都會觸發一次上面的回調函數,在該回調函數的實現中,即可得到查詢結果。
在上面的Result函數中,各個參數意義如下:
| pContext |
這個參數是調用sqlite3_exec函數是輸入的第4個參數。它通常作為環境變量用於指示出當前執行代碼的主體。示例代碼中我忽略了這個參數,但正式使用時一般不會忽略它。 |
| nCol |
表示該條記錄有多少列。 |
| azValue |
返回的數據都蘊含在該變量中,它也是一個字符串數組。azValue[n]即為第n列的數據。 |
| azName |
存放列的名稱,azName[n]就是第n列的名稱。 |
考慮到sqlite作為輕量級數據庫我很少用它存儲二進制數據,因此本文之前並未詳細解決二進制數據的存取。
但后來我發現實際使用時候,有時候存儲一些二進制數據也是很必要的,比如一些簡單的圖片。另外一些可能包含一些sql語句的保留字符的文本時,如果想避免進行字符串檢查,也可以考慮當作二進制數據存取。
在sqlite中,二進制數據的數據類型為blob,本文還是以代碼來示范其應用,包括創建表格、存入二進制數據,讀出二進制數據。
向數據庫中存入二進制數據過程大體如下:
1.使用sqlite3_prepare進行sql語句准備,其中二進制內容以"?"替代;
2.以sqlite3_bind_blob將"?"的內容以二進制數據填充。
3.調用sqlite3_step執行sql語句完成存入操作。
從數據庫中讀取二進制數據過程大體如下:
1.使用sqlite3_prepare語句進行查詢行為;
2.調用sqlite3_step獲得查詢到的結果,第一次調用時,返回查詢到的第一行數據;
3.調用sqlite3_column_blob獲得二進制數據指針,調用sqlite3_column_bytes獲得二進制數據長度,兩者結合可以獲得完整二進制數據。
4.繼續執行第二步,獲得查詢到的下一條結果。
其余詳情,可以參看代碼示例:
//打開數據庫(不存在則自動創建) sqlite3* db = NULL; int result = sqlite3_open("C:\\TestBlob.db", &db); if(SQLITE_OK != result) { return; } //創建數據表(本次不檢查返回結果,由於數據表不允許重復創建,因此只有首次執行才會成功) result = sqlite3_exec(db, "CREATE TABLE tb" //創建的表名為tb "(id integer NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE" //第一列使用一個自動增長的integer數據 ", b1 blob" //第二列為blob類型,列名為b1 ", b2 blob);" //第三列為blob類型,列名為b2 , 0, 0, 0); //此處我不再精心構造二進制數據了,隨便用兩個字符串替代用作演示 //blob1我隨便加了幾個經常會導致sql語句出問題的字符 std::string blob1 = "abc'<?%", blob2 = "bcd"; //准備一個statement用於后續進行二進制操作 sqlite3_stmt* stmt = NULL; //准備執行包含二進制數據的sql操作中,注意下面的兩個“?”表示的是二進制數據 sqlite3_prepare(db, "insert into tb (b1, b2) values (?, ?);", -1, &stmt, NULL); //下面以二進制數據分別填充這兩個"?",注意序號從1開始的 sqlite3_bind_blob(stmt, 1, blob1.data(), blob1.length(), NULL); sqlite3_bind_blob(stmt, 2, blob2.data(), blob2.length(), NULL); //真正開始執行前面的sql語句 sqlite3_step(stmt); //釋放前面為stmt分配的內存,必須要有,否則會有內存泄露 sqlite3_finalize(stmt); // //**接下來,演示一下如何讀取插入的數據 // //讀取二進制數據 result = sqlite3_prepare(db, "select * from tb", -1, &stmt, 0); while (SQLITE_ROW == sqlite3_step(stmt)) { //借助兩個string來讀取反饋結果(僅供演示) std::string blobRet1, blobRet2; //示范一下如何讀取整形數據 int id = sqlite3_column_int(stmt, 0); //示范一下如何讀取二進制數據 blobRet1.append( (char *)sqlite3_column_blob(stmt, 1) , sqlite3_column_bytes(stmt, 1) ); //讀取blob2的內容 blobRet2.append( (char *)sqlite3_column_blob(stmt, 2) , sqlite3_column_bytes(stmt, 2) ); } //**如果希望從頭遍歷一次反饋的結果,調用sqlite3_reset(stmt);可以達到此效果 //同樣需要記得釋放資源 sqlite3_finalize(stmt); //關閉數據庫 sqlite3_close(db);
