C/C++中Sqlite使用簡介


一、簡介

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語句

執行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)
 
2、插入記錄

下面是插入一條記錄的示例SQL語句。

INSERT INTO MyTable (MyText, MyDate, MyTime, MyFloat) VALUES ('---上班好遠!', '2012-03-23', '9:00:00', 1000)
 
3、更新記錄

下面是更新若干條記錄的示例SQL語句。

UPDATE MyTable SET MyText='真的嗎?', MyTime='10:00:00' WHERE ID >=0 AND ID <=20
 
4、刪除記錄

下面是刪除若干條記錄的示例SQL語句。

DELETE FROM MyTable WHERE ID >=3 AND ID <=5
 
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); 
 
七、查詢並返回結果 
 
1、以表單形式返回

下面是以表單形式獲取數據的示例代碼:

//查詢記錄(返回數據表的方式)
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);
上面的查詢代碼,也演示了如何查詢指定位置指定條數的記錄,這種查詢方法在記錄集非常龐大的時候很有用。

 

2、以回調形式返回

下面以代碼形式示例如何獲得查詢語句返回的記錄。

首先需要定義一個回調函數如下(參數意義待會再說):

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); 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM