SQLite C/C++接口簡介
原文 http://segmentfault.com/a/1190000002771737
翻譯自 https://www.sqlite.org/cintro.html ,建議閱讀原文
摘要
接下來的兩個對象和八個方法包含了SQLite接口的基本要素:
- sqlite3 數據庫連接對象. 由sqlite3_open()創建,由sqlite3_close()銷毀。
- sqlite3_stmt 預編譯語句對象. 由 sqlite3_prepare() 創建,由 sqlite3_finalize() 銷毀。
- sqlite3_open() 打開已存在或者新建數據庫的連接。 sqlite3 的構造函數。
- sqlite3_prepare() 將SQL文本編譯成字節碼,以便于執行查詢或者更新數據庫的操作 sqlite3_stmt 的構造函數。
- sqlite3_bind() 將應用程序的數據與原始SQL中的 參數 綁定
- sqlite3_step() 執行 sqlite3_stmt 到下一個結果或者結束
- sqlite3_column() 當前結果行所在的列值
- sqlite3_finalize() sqlite3_stmt 的析構函數。
- sqlite3_close() sqlite3 的析構函數。
- sqlite3_exec() 一個包裝函數,為一條或多條SQL語句包裝了 sqlite3_prepare() , sqlite3_step() , sqlite3_column() , 和 sqlite3_finalize() 。
簡介
早期的SQLite只支持五個C/C++接口,所以非常容易學習。但是隨著SQLite的不斷壯大,新的C/C++接口不斷加入,目前已有超過 200個不同的接口。這能輕易壓倒一個新手程序員。幸運的是,大部分SQLite的C/C++接口非常專業并且你不需要去關心。盡管有如此多的切入 點,SQLite的核心API依然比較簡單易于學習,易于編程。這篇文章旨在提供所有必需的背景信息以便于讓你理解SQLite是如何工作的。
這份單獨的文檔, SQLite C/C++接口 ,提供了所有SQLite C/C++ 接口的詳細說明。當讀者理解了SQLite操作的基本原則,這份文檔可以作為參考指南使用。本文章目的僅僅是介紹,而不是SQLite API 的完整或者權威的指南。
核心對象和接口
SQL數據庫引擎的主要任務是執行SQL語句。為了實現這個目的,開發者需要知道這兩個對象:
嚴格得講,有了便捷的包裝接口預編譯語句對象,sqlite3_exec 或者 sqlite3_get_table之后, 預編譯語句 對象不再是必須的。因為可以使用這些便捷的包裝器封裝和隱藏 預編譯語句 對象。但是要充分利用SQLite需要理解預編譯語句對象。
數據庫連接 和 預編譯語句 對象是由以下列出的一部分接口控制:
這六個C/C++接口程序和上述的兩個對象來自于SQLite基礎功能的核心。理解了它們,開發者將能更好得使用SQLite。
請注意上述的程序是概念性的而不是實際上的。這些程序大都存在多個版本。比如上面列表只顯示了單個名為 sqlite3_open() 的程序,但實際上有三個獨立的程序以不同的方式完成同樣的事情: sqlite3_open() , sqlite3_open16() 和 sqlite3_open_v2() 。另外列表里還提及了 sqlite3_column() ,但實際上并沒有這樣的程序存在。列表中顯示的"sqlite3_column()"代表的是這個程序整個家族,它們被用于提取不同類型的列數據。
這里總結一下核心接口會做什么:
-
sqlite3_open() 用來打開一個數據庫文件的連接并返回數據庫連接對象。這通常是應用調用的第一個SQLite API,低于大多數其他的SQLite API這是先決條件。許多SQLite接口需要一個指向數據庫連接的指針作為第一個參數,也可以認為是數據庫連接對象的方法。 sqlite3_open()是數據庫連接對象的構造方法。
-
sqlite3_prepare() 將SQ文本轉換為預編譯語句對象并返回該對象的指針。這個接口需要一個由sqlite3_open()創建的指向數據庫連接的指針和一段包含SQL語句的文本。這個API并非真正得執行SQL語句,僅僅準備需要執的SQL語句。
把每條SQL語句想象成一個小的計算機程序。sqlite3_prepare()的目的是將程序編譯成目標代碼。預編譯語句是目標代碼。接著sqlite3_step()接口運行目標代碼并得到結果。
請注意對于新的應用不建議使用sqlite3_prepare(),而應使用架構更新的程序sqlite3_prepare_v2()代替。
-
sqlite3_step() 用來執行之前由sqlite3_prepare()接口創建的預編譯語句。這語句執行到第一行可用的位置。若要執行結果的第二行,需要再次調用 sqlite3_step()。繼續調用 sqlite3_step()直到語句結束。對于那些不返回結果的語句(比如: INSERT, UPDATE, 或者DELETE),只需調用一次sqlite3_step()。
-
sqlite3_column() 從sqlite3_step()執行的準備語句得到的結果集的當前行中返回一個列。每次sqlite3_step()得到一個結果集的列后,這個過程就可 以被多次調用去查詢這個行的各列的值。正如上面提到的那樣,在SQLite API中并沒有這個一個"sqlite3_column()"函數。取而代之的是整個 "sqlite3_column()"家族,用于返回不同數據類型的結果。在這個家族里也有函數用來返回結果的大小(如果類型是string或者 BLOB)和結果集列的數量。
- sqlite3_column_blob()
- sqlite3_column_bytes()
- sqlite3_column_bytes16()
- sqlite3_column_count()
- sqlite3_column_double()
- sqlite3_column_int()
- sqlite3_column_int64()
- sqlite3_column_text()
- sqlite3_column_text16()
- sqlite3_column_type()
- sqlite3_column_value()</pre> </li>
可以用來打開存在的數據庫文件也能創建新的數據庫文件。盡管很多的應用僅僅使用單個數據庫連接時,但也沒有任何理由不能多次調用 sqlite3_open()創建多個數據庫連接,同一個數據庫或者不同的數據庫。多線程的應有時會為每個線程創建不同的數據庫連接。還要注意,沒有必要 為了訪問兩個或者多個數據庫而創建不同的數據庫連接。單個數據庫連接可以使用 ATTACH SQL命令同時訪問兩個或者多個數據庫。<li> <p> <a href="/misc/goto?guid=4959632414692213299">sqlite3_finalize()</a> 銷毀由sqlite3_prepare()創建的預編譯語句。為了防止內存泄露,每條預編譯語句必須調用這個方法進行銷毀。 </p> </li> <li> <a href="/misc/goto?guid=4959632415268555047">sqlite3_close()</a> 關閉由sqlite3_open()創建的數據庫連接。在關閉連接之前,所有的預編譯語句都應該被finalize。 </li> </ul> <h2> 核心程序和接口的典型用法 </h2> <p> 應用若要使用SQLite通常的做法是在初始化的時候通過sqlite3_open()創建單個數據庫連接。注意sqlite3_open()
了使用這類的靈活性,SQLite允許將要執行的SQL語句包含之前綁定的參數。這些值可以在后面更改,這樣相同的預編譯語句可以使用新的值執行第二次。</p> <p> 大多數應用的做法是在關閉時調用sqlite3_close()銷毀數據庫連接。或者例如一個應用使用SQLite作為文件格式,在文件/打開菜單操作時打開數據庫連接,在文件/關閉菜單時銷毀相應的數據庫連接。 </p> <p> 若要運行SQL語句,請遵循以下步驟: </p> <ul> <li> 使用 <a href="/misc/goto?guid=4959632414615686124">sqlite3_prepare()</a> .創建預編譯語句對象。 </li> <li> 調用 <a href="/misc/goto?guid=4959632415070024313">sqlite3_step()</a> 一次或者多次執行預編譯語句對象 </li> <li> 對于查詢來說,調用 <a href="/misc/goto?guid=4959632415156075912">sqlite3_column()</a> 提取執行 <a href="/misc/goto?guid=4959632415070024313">sqlite3_step()</a> 得到的結果集 </li> <li> 使用 <a href="/misc/goto?guid=4959632414692213299">sqlite3_finalize()</a> 來銷毀預編譯語句 </li> </ul> <p> 為了更加有效得使用SQLite,以上是需要了解的。剩下的就只有細枝末節。 </p> <h2> 方便的包裝器 </h2> <p> <a href="/misc/goto?guid=4959632415365663143">sqlite3_exec()</a> 接口是一個方便的包裝器,調用一個方法便可執行上面的四個步驟。傳遞到 <a href="/misc/goto?guid=4959632415365663143">sqlite3_exec()</a> 中的回調函數將用于處理每行結果集。 <a href="/misc/goto?guid=4959632415868753296">sqlite3_get_table()</a> 是另一個方便的包裝器,同樣可以用上述的四個步驟。與 <a href="/misc/goto?guid=4959632415365663143">sqlite3_exec()</a> 不同的是, <a href="/misc/goto?guid=4959632415868753296">sqlite3_get_table()</a> 將結果存儲在堆存儲器里而非調用回調函數。 </p> <p> 無論是 <a href="/misc/goto?guid=4959632415365663143">sqlite3_exec()</a> 還是 <a href="/misc/goto?guid=4959632415868753296">sqlite3_get_table()</a> 做的任何事情都可以由核心程序來完成,認識到這一點很重要。事實上,這些包裝器僅僅實現了核心程序。 </p> <h2> 綁定參數與重用預編譯語句 </h2> <p> 在之前的討論中,假設了每條SQL語句只準備,執行了一次然后銷毀。但是SQLite允許相同的預編譯語句執行多次。這由以下的程序完成: </p> <ul> <li> <a href="/misc/goto?guid=4959632415980635367">sqlite3_reset()</a> </li> <li> <a href="/misc/goto?guid=4959632414889727077">sqlite3_bind()</a> </li> </ul> <p> 在 <a href="/misc/goto?guid=4959632414521437674">預編譯語句</a> 被一次或多次調用 <a href="/misc/goto?guid=4959632415070024313">sqlite3_step()</a> 執行之后,它可以通過調用 <a href="/misc/goto?guid=4959632415980635367">sqlite3_reset()</a> 重置以便于再次執行。對已存在的預編譯語句對象使用 <a href="/misc/goto?guid=4959632415980635367">sqlite3_reset()</a> 而不是創建一個新的預編譯語句,避免不必要得調用 <a href="/misc/goto?guid=4959632414615686124">sqlite3_prepare()</a> 。對于很多SQL語句來說,執行sqlite3_prepare()的時間等于或者超過執行sqlite3_step()的時間。所以避免調用sqlite3_prepare()可以顯著提升性能。 </p> <p> 通常情況下,盡管多次執行相同的SQL語句并非有用。更多時候,執行的是相似的語句。比如你可能想要多次執行一條插入語句,但插入的值不同。為
進程級的配置完成之后 數據庫連接 便會建立。個別的數據庫連接可以調用 sqlite3_limit() 和 sqlite3_db_config() 進行配置。</p> <p> 在SQLite中,無論是否有效得包含字符串,都可以選取以下的形式作為參數: </p> <ul> <li> ? </li> <li> ?NNN </li> <li> :AAA </li> <li> $AAA </li> <li> @AAA </li> </ul> <p> 在上面的例子中,NNN是整數值,AAA是標識符。參數初始化值為NULL。首先先調用 <a href="/misc/goto?guid=4959632415070024313">sqlite3_step()</a> 或者在 <a href="/misc/goto?guid=4959632415980635367">sqlite3_reset()</a> 立即調用。應用可以調用其中一個sqlite3_bind()接口附加到參數上。每次調用 <a href="/misc/goto?guid=4959632414889727077">sqlite3_bind()</a> 將覆蓋先前的參數綁定。 </p> <p> 應用程序可以提前準備多條SQL語句,并根據需要對其執行。對于準備的語句在數量上沒有任何限制。 </p> <h2> 配置SQLite </h2> <p> 對于大多數應用來說SQLite的默認配置已經足夠了。但是有時開發者想要調整設,以盡量提升一點性能,或者使用一些不起眼的特性。 </p> <p> <a href="/misc/goto?guid=4959632416165658055">sqlite3_config()</a> 接口用于創建SQLite全局的,進程級的配置更改。在任何數據庫連接被創建前,sqlite3_config()接口必須被調用。 <a href="/misc/goto?guid=4959632416165658055">sqlite3_config()</a> 接口允許程序員做這樣的事情: </p> <ul> <li> 調整SQLite內存分配,包括為實時嵌入系統設置內存分配器和設置應用定義的 <a href="/misc/goto?guid=4959632416259138569">內存分配器</a> 。 </li> <li> 設置進程級的 <a href="/misc/goto?guid=4959632416344874016">錯誤日志</a> </li> <li> 指定應用定義的頁面緩存 </li> <li> 調整互斥體使之適合于不同的 <a href="/misc/goto?guid=4959632416429663000">線程模型</a> ,或者替換應用定義的互斥系統 <br />
</div> </div></li> </ul> <h2> 擴展SQLite </h2> <p> SQLite還包括了用來擴展功能的接口,這些程序包括: </p> <ul> <li> <a href="/misc/goto?guid=4959632416683597006">sqlite3_create_collation()</a> </li> <li> <a href="/misc/goto?guid=4958539522935969758">sqlite3_create_function()</a> </li> <li> <a href="/misc/goto?guid=4959632416793951857">sqlite3_create_module()</a> </li> <li> <a href="/misc/goto?guid=4959632416884363124">sqlite3_vfs_register()</a> </li> </ul> <p> sqlite3_create_collation()接口用來為排序文本創建新的排序序列。 <a href="/misc/goto?guid=4959632416793951857">sqlite3_create_module()</a> 接口用來注冊新的 <a href="/misc/goto?guid=4959632416970123841">虛擬表</a> 實現。 <a href="/misc/goto?guid=4959632416884363124">sqlite3_vfs_register(</a> )接口創建新的 <a href="/misc/goto?guid=4959632417077983889">VFSes</a> 。 </p> <p> <a href="/misc/goto?guid=4958539522935969758">sqlite3_create_function()</a> 接口創建新的SQL功能 - 無論是標量還是聚合。新功能的實現通常使用了以下幾個附加接口: </p> <ul> <li> <a href="/misc/goto?guid=4959632417169147416">sqlite3_aggregate_context()</a> </li> <li> <a href="/misc/goto?guid=4959632417243730767">sqlite3_result()</a> </li> <li> <a href="/misc/goto?guid=4959632417331880171">sqlite3_user_data()</a> </li> <li> <a href="/misc/goto?guid=4959632417409568784">sqlite3_value()</a> </li> </ul> <p> SQLite所有內置的SQL函數正式使用這些接口來創建的。參考SQLite源碼,特別是date.c和func.c源文件的例子。 </p> <p> 共享的庫或 Dll 可以用作 SQLite 的 <a href="/misc/goto?guid=4958539522300076698">可加載擴展</a> 。 </p> <h2> 其他接口 </h2> <p> 這篇文章僅僅提及了SQLite接口的基礎功能。SQLite庫還包含了很多其他有用的特性但是這里沒有描述。你能在 <a href="/misc/goto?guid=4959632415483783314">C/C++接口規范</a> 中找到SQLite完整的功能列表。請參閱關于SQLite所有接口的權威文檔。 </p>