一、SQLite 簡介
1.介紹
SQLite,是一款輕型的數據庫,是遵守ACID的關系型數據庫管理系統,它包含在一個相對小的C庫中。它是D.RichardHipp建立的公有領域項目。它的設計目標是嵌入式的,
而且目前已經在很多嵌入式產品中使用了它,它占用資源非常的低,在嵌入式設備中,可能只需要幾百K的內存就夠了。它能夠支持Windows/Linux/Unix等等主流的操作系統,
同時能夠跟很多程序語言相結合,比如 Tcl、C#、PHP、Java等,還有ODBC接口,同樣比起Mysql、PostgreSQL這兩款開源的世界著名數據庫管理系統來講,它的處理速度比他們都快。
SQLite第一個Alpha版本誕生於2000年5月。 至2015年已經有15個年頭,SQLite也迎來了一個版本 SQLite 3已經發布
SQLite是一個進程內的庫,實現了自給自足的、無服務器的、零配置的、事務性的 SQL 數據庫引擎。它是一個零配置的數據庫,這意味着與其他數據庫一樣,您不需要在系統中配置。
就像其他數據庫,SQLite 引擎不是一個獨立的進程,可以按應用程序需求進行靜態或動態連接。SQLite 直接訪問其存儲文件。
2.特點
1).不需要一個單獨的服務器進程或操作的系統(無服務器的)。
2).SQLite 不需要配置,這意味着不需要安裝或管理。
3).一個完整的 SQLite 數據庫是存儲在一個單一的跨平台的磁盤文件。
4).SQLite 是非常小的,是輕量級的,完全配置時小於 400KiB,省略可選功能配置時小於250KiB。
5).SQLite 是自給自足的,這意味着不需要任何外部的依賴。
6).SQLite 事務是完全兼容 ACID 的,允許從多個進程或線程安全訪問。
7).SQLite 支持 SQL92(SQL2)標准的大多數查詢語言的功能。
8).SQLite 使用 ANSI-C 編寫的,並提供了簡單和易於使用的 API。
9).SQLite 可在 UNIX(Linux, Mac OS-X, Android, iOS)和 Windows(Win32, WinCE, WinRT)中運行。
10).數據庫文件可以在不同字節順序的機器間自由的共享
11).支持數據庫大小至2TB
12).足夠小, 大致13萬行C代碼, 4.43M
13).比一些流行的數據庫在大部分普通數據庫操作要快
14).簡單, 輕松的API
15).包含TCL綁定, 同時通過Wrapper支持其他語言的綁定
16).良好注釋的源代碼, 並且有着90%以上的測試覆蓋率
17).獨立: 沒有額外依賴
18).源碼完全的開源, 你可以用於任何用途, 包括出售它
19).支持多種開發語言,C, C++, PHP, Perl, Java, C#,Python, Ruby等
3.支持的SQL
SQLite雖然很小巧,但是支持的SQL語句不會遜色於其他開源數據庫,
它支持的SQL主要包括:
DDL - 數據定義語言
CREATE 創建一個新的表,一個表的視圖,或者數據庫中的其他對象。
ALTER 修改數據庫中的某個已有的數據庫對象,比如一個表。
DROP 刪除整個表,或者表的視圖,或者數據庫中的其他對象。
DML - 數據操作語言
INSERT 創建一條記錄。
UPDATE 修改記錄。
DELETE 刪除記錄。
DQL - 數據查詢語言
SELECT 從一個或多個表中檢索某些記錄。
具體包括:
ATTACH DATABASE
BEGIN TRANSACTION
comment
COMMIT TRANSACTION
COPY
CREATE INDEX
CREATE TABLE
CREATE TRIGGER
CREATE VIEW
DELETE
DETACH DATABASE
DROP INDEX
DROP TABLE
DROP TRIGGER
DROP VIEW
END TRANSACTION
EXPLAIN
expression
INSERT
ON CONFLICT clause
PRAGMA
REPLACE
ROLLBACK TRANSACTION
SELECT
UPDATE
同時它還支持事務處理功能等等。也有人說它象Microsoft的Access,有時候真的覺得有點象,但是事實上它們區別很大。
比如SQLite 支持跨平台,操作簡單,能夠使用很多語言直接創建數據庫,而不象Access一樣需要Office的支持。
如果你是個很小型的應用,或者你想做嵌入式開發,沒有合適的數據庫系統,那么你可以考慮使用SQLite。
到2013年10月17日最新版本是 3.8.1 。能在上面獲得源代碼和文檔。同時因為數據庫結構簡單,系統源代碼也不是很多,
也適合想研究數據庫系統開發的專業人士.
二、SQLite 安裝
SQLite 的一個重要的特性是零配置的,這意味着不需要復雜的安裝或管理。本章將講解 Windows、Linux 和 Mac OS X 上的安裝設置。
1.在 Windows 上安裝 SQLite
請訪問 https://www.sqlite.org/download.html,從 Windows 區下載預編譯的二進制文件。
您需要下載 sqlite-tools-win32-*.zip 和 sqlite-dll-win32-*.zip 壓縮文件。
創建文件夾 C:\sqlite,並在此文件夾下解壓上面兩個壓縮文件,將得到 sqlite3.def、sqlite3.dll 和 sqlite3.exe 文件。
添加 C:\sqlite 到 PATH 環境變量,最后在命令提示符下,使用 sqlite3 命令,將顯示如下結果。
C:\>sqlite3
SQLite version 3.7.15.2 2013-01-09 11:53:05
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite>
2.在 Linux 上安裝 SQLite
目前,幾乎所有版本的 Linux 操作系統都附帶 SQLite。所以,只要使用下面的命令來檢查您的機器上是否已經安裝了 SQLite。
$sqlite3
SQLite version 3.7.15.2 2013-01-09 11:53:05
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite>
如果沒有看到上面的結果,那么就意味着沒有在 Linux 機器上安裝 SQLite。因此,讓我們按照下面的步驟安裝 SQLite:
請訪問 https://www.sqlite.org/download.html,從源代碼區下載 sqlite-autoconf-*.tar.gz。
步驟如下:
$tar xvfz sqlite-autoconf-3071502.tar.gz
$cd sqlite-autoconf-3071502
$./configure --prefix=/usr/local
$make
$make install
上述步驟將在 Linux 機器上安裝 SQLite,您可以按照上述講解的進行驗證。
3.在 Mac OS X 上安裝 SQLite
最新版本的 Mac OS X 會預安裝 SQLite,但是如果沒有可用的安裝,只需按照如下步驟進行:
請訪問 https://www.sqlite.org/download.html,從源代碼區下載 sqlite-autoconf-*.tar.gz。
步驟如下:
$tar xvfz sqlite-autoconf-3071502.tar.gz
$cd sqlite-autoconf-3071502
$./configure --prefix=/usr/local
$make
$make install
上述步驟將在 Mac OS X 機器上安裝 SQLite,您可以使用下列命令進行驗證:
$sqlite3
SQLite version 3.7.15.2 2013-01-09 11:53:05
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite>
最后,在 SQLite 命令提示符下,使用 SQLite 命令做練習。
三、SQLite的數據類型
首先你會接觸到一個讓你驚訝的名詞: Typelessness(無類型). 對! SQLite是無類型的. 這意味着你可以保存任何類型的數據到你所想要保存的任何表的任何列中, 無論這列聲明的數據類型是什么(只有在一種情況下不是, 稍后解釋). 對於SQLite來說對字段不指定類型是完全有效的. 如:
Create Table ex1(a, b, c);
誠然SQLite允許忽略數據類型, 但是仍然建議在你的Create Table語句中指定數據類型. 因為數據類型對於你和其他的程序員交流, 或者你准備換掉你的數據庫引擎時能起到一個提示或幫助的作用. SQLite支持常見的數據類型, 如:
CREATE TABLE ex2
a VARCHAR(10),
b NVARCHAR(15),
c TEXT,
d INTEGER,
e FLOAT,
f BOOLEAN,
g CLOB,
h BLOB,
i TIMESTAMP,
j NUMERIC(10,5)
k VARYING CHARACTER (24),
l NATIONAL VARYING CHARACTER(16)
前面提到在某種情況下, SQLite的字段並不是無類型的. 即在字段類型為”Integer Primary Key”時.
四、SQLite3 C語言操作
SQLite提供了一系列接口供用戶訪問數據庫,主要包括連接數據庫,處理SQL,迭代查詢結果等
我們下載sqlite源碼包(https://www.sqlite.org/sqlite-amalgamation-3071400.zip),只需要其中的sqlite3.c、sqlite.h即可。
(說明:libsqlite3.so是從sqlite3.c編譯而來的, sqlite3可運行文件是從shell.c編譯而來的)
1.數據庫的操作
1).打開數據庫
可以使用函數sqlite3_open_v2( )、 sqlite3_open( ) 、sqlite3_ open16( )。
其中sqlite3_open_v2( )函數功能最強大,也是最新的函數,盡量使用這個函數
sqlite3_open_v2
原型:
int sqlite3_open_v2(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
int flags, /* Flags */
const char *zVfs /* Name of VFS module to use */
);
作用:打開一個數據庫連接
關鍵的參數:flags
SQLITE_OPEN_NOMUTEX: 設置數據庫連接運行在多線程模式(沒有指定單線程模式的情況下)
SQLITE_OPEN_FULLMUTEX:設置數據庫連接運行在串行模式。
SQLITE_OPEN_SHAREDCACHE:設置運行在共享緩存模式。
SQLITE_OPEN_PRIVATECACHE:設置運行在非共享緩存模式。
SQLITE_OPEN_READWRITE:指定數據庫連接可以讀寫。
SQLITE_OPEN_CREATE:如果數據庫不存在,則創建。
2).關閉數據庫
sqlite3_close_v2
原型:
int sqlite3_close_v2(sqlite3*);
作用:關閉數據庫連接,若關閉時連接上有未提交的事務,該事務會自動回滾。
3).例子:打開關閉數據庫連接
sqlite3* pDb;
char* filename="/u01/sqlite/test.db";
sqlite3_open_v2(filename, &pDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_SHAREDCACHE, NULL);
....
....
sqlite3_close_v2(pDb);
打開數據庫文件test.db,對應的數據庫連接可讀可寫,以多線程模式運行,並且運行在共享緩存模式,
執行完操作后,關閉數據庫連接。
2.表的操作
1).更新SQL主要包括創建表,插入,刪除,更新記錄等
SQLite中常用的更新API有兩個,一個是sqlite3_exec,另外一個是sqlite3_prepare_v2。
(1).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可以包含多個SQL命令,語句之間以分號隔開,sqlite3_exec()將解析和執行sql字符串中的每個命令,直到到達該字符串的末尾或遇到錯誤。
對於運行修改數據庫的命令(創建,插入,刪除,更新)非常適合,一個函數調用就可以完成全部操作。
需要注意的是,雖然sqlite3_exec()可以執行多個SQL命令,但是函數不保證事務,即已執行成功的語句,不會因為后面執行失敗的語句而回滾。
(2).sqlite3_perpare_v2
原型:
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 */
);
sqlite3_exec實際上是將編譯,執行進行了封裝,與之等價的一組函數是 sqlite3_prepare_v2(), sqlite3_step()和sqlite3_finalize()。
sqlite3_prepare_v2()編譯SQL語句生成VDBE執行碼,sqlite3_step()執行,sqlite3_finalize()關閉語句句柄,釋放資源。
兩種方式,都可以通過調用sqlite3_changes(pdb),得到語句影響的行數。
(3).兩種方式比較
.sqlite3_exec方式接口使用很簡單,實現同樣的功能,比sqlite3_perpare_v2接口代碼量少。
.sqlite3_prepare方式更高效,因為只需要編譯一次,就可以重復執行N次。
.sqlite3_prepare方式支持參數化SQL。
鑒於兩種方式的差異,對於簡單的PRAGMA設置語句(PRAGMA cache_size=2000),事務設置語句(BEGIN TRANSACTION,COMMIT,ROLLBACK)使用sqlite3_exec方式,更簡單;
而對於批量的更新、查詢語句,則使用sqlite3_prepare方式,更高效。
(4).例子:prepare方式執行多sql的例子,pNext初始化在sql語句首部,執行完一個sql后,移動到下一個sql首部
const char *pNext = (const char *)sql;
while (pNext && strlen(pNext) > 0) {
rc = sqlite3_prepare_v2(pDb, pNext, -1, &pStmt, &pNext);
if(SQLITE_OK != rc){
錯誤處理
break;
}
rc = sqlite3_step(pStmt);
if(SQLITE_OK != rc && SQLITE_DONE != rc){
錯誤處理
break;
}
rc = SQLITE_OK;
/*統計影響記錄數目*/
resultCount += sqlite3_changes(pDb);
/* 清理語句句柄,准備執行下一個語句*/
sqlite3_finalize(pStmt);
}
2).創建表
#include <stdio.h>
#include "sqlite3.h"
int main(int argc,char *argv[]){
const char *sql_create_table="create table t(id int primary key,msg varchar(128))";
char *errmsg = 0;
int ret = 0;
sqlite3 *db = 0;
ret = sqlite3_open("./sqlite3-demo.db",&db);
if(ret != SQLITE_OK){
fprintf(stderr,"Cannot open db: %s\n",sqlite3_errmsg(db));
return 1;
}
printf("Open database\n");
ret = sqlite3_exec(db,sql_create_table,NULL,NULL,&errmsg);
if(ret != SQLITE_OK){
fprintf(stderr,"create table fail: %s\n",errmsg);
}
sqlite3_free(errmsg);
sqlite3_close(db);
printf("Close database\n");
return 0;
}
3.記錄的操作
1).執行查詢
執行查詢和前面創建表說的一樣,使用的api可以是兩個中的一個:
一個是sqlite3_exec,另外一個是sqlite3_prepare_v2
然后api中傳入sql語句即可。
2).獲取查詢結果集
(1).sqlite3_get_table
原型:
int sqlite3_get_table(
sqlite3 *db, /* An open database */
const char *zSql, /* SQL to be evaluated */
char ***pazResult, /* Results of the query */
int *pnRow, /* Number of result rows written here */
int *pnColumn, /* Number of result columns written here */
char **pzErrmsg /* Error msg written here */
);
該函數接收SQL語句返回的所有記錄,使用sqlite內部分配的內存,將其存儲在參數resultp中,
必須使用sqlite3_free_table()釋放內存。由於結果集可能非常大,會導致內存撐爆,因此對於大結果集的查詢,不建議采用這種方式。
(2).sqlite3_prepare_v2
prepare方式同樣支持查詢語句,主要分為3個階段,編譯,執行和結果集處理。
前面更新SQL部分已經描述了prepare的基本步驟,這里主要講結果集處理部分。
首先通過sqlite3_column_count()可以得到結果集的列數目,
通過sqlite3_column_type()可以得到具體某列的存儲類型,方便我們調用合適的sqlite3_column_xxx接口處理字段值。
主要有以下幾類:
sqlite3_column_int
sqlite3_column_int64
sqlite3_column_double
sqlite3_column_text
sqlite3_column_blob
(3).例子:遍歷結果集
int rc = sqlite3_prepare_v2(pDb, sql, -1, &pStmt, NULL);
//獲取列數目
int n_columns = sqlite3_column_count(pStmt);
do{
ret = sqlite3_step(stmt);
if (ret == SQLITE_ROW)
{
//處理每一列
for (i = 0; i < n_columns; i++)
{
/*獲取列存儲類型*/
type = sqlite3_column_type(stmt,i);
switch(type)
{
case SQLITE_INTEGER:
/*處理整型*/
sqlite3_column_int(stmt,i);
break;
case SQLITE_FLOAT:
/*處理浮點數*/
sqlite3_column_double(stmt,i);
break;
case SQLITE_TEXT:
/*處理字符串*/
sqlite3_column_text(stmt,i);
break;
case SQLITE_BLOB:
/*處理二進制*/
sqlite3_column_blob(stmt, i));
break;
case SQLITE_NULL:
/*處理空*/
}
}
}
else if (ret == SQLITE_DONE) //結束
{
break;
}
}while(true);
4.預編譯操作
SQLite通過prepare接口可以支持參數化的SQL語句,即帶問號的SQL語句。比如查詢語句select * from t where id=?,
或者插入語句 insert into t(a,b,c) values(?,?,?)。通過參數化SQL,可以實現一次編譯多次執行的目的
1).預編譯操作的流程
預編譯操作比較麻煩的,完整的預編譯操作的流程是:
通過sqlite3_prepare_v2()創建一個sqlite3_stmt對象
通過sqlite3_bind_*()綁定預編譯字段的值
通過sqlite3_step()執行SQL語句
通過sqlite3_reset()重置預編譯語句,重復操作2多次
通過sqlite3_finalize()銷毀資源
其中,
調用sqlite3_bind_xxx接口來綁定具體的參數。主要有以下幾類:
sqlite3_bind_int
sqlite3_bind_int64
sqlite3_bind_double
sqlite3_bind_text
sqlite3_bind_blob
sqlite3_bind_null
關於綁定參數這里提一點,對於sqlite3_bind_text和sqlite3_bind_blob接口,綁定參數占據的存儲空間是否可以被SQLite重用。接口中通過最后一個參數指定,參數值可以為SQLITE_STATIC和SQLITE_TRANSIENT。
SQLITE_STATIC:通知bind函數,參數使用空間是常量,不會改變,sqlite內部無需拷貝副本。
SQLITE_TRANSIENT:通知bind函數,參數使用空間可能會改變,sqlite內部需要有自己的副本
2).預編譯SQL語句中可以包含如下幾種形式:
?
?NNN
:VVV
@VVV
$VVV
NNN代表數字,VVV代表字符串。
如果是?或者?NNN,那么可以直接sqlite3_bind_*()進行操作,如果是字符串,還需要通過sqlite3_bind_parameter_index()獲取對應的index,
然后再調用sqlite3_bind_*()操作。這通常用於構造不定條件的SQL語句(動態SQL語句)。
3).例子:批量導入
//begin a transaction
if(sqlite3_exec(pdb, "begin", NULL, NULL, &errmsg) != SQLITE_OK)
{
錯誤處理
return ERROR;
}
sqlite3_prepare_v2(pdb, "insert into t1 values(?,?,?);", &stmt);
for (i = 0; i < n_rows; i++)
{
for (j = 0; j < n_columns; j++)
{
switch(type)
{
case SQLITE_INTEGER:
/*處理整型*/
sqlite3_bind_int()
break;
case SQLITE_FLOAT:
/*處理浮點型*/
sqlite3_bind_double()
break;
case SQLITE_TEXT:
/*處理字符串類型*/
sqlite3_bind_text()
break;
case SQLITE_BLOB:
/*處理二進制類型*/
sqlite3_bind_blob
break;
case SQLITE_NULL:
sqlite3_bind_null(stmt, index);
break;
}
}
sqlite3_step(stmt); //執行
sqlite3_reset(stmt); //將已編譯的SQL語句恢復到初始狀態,保留語句相關的資源
}
sqlite3_finalize(stmt); //結束語句,釋放語句句柄
if(sqlite3_exec(pdb, "commit", NULL, NULL, &errmsg) != SQLITE_OK)
{
錯誤處理 return ERROR;
}
5.錯誤與異常:
錯誤處理:
API可能返回錯誤的整數結果代碼。比如:sqlite3_open_v2() 、sqlite3_prepare()sqlite3_exec()、sqlite3_bind_xxx()、sqlite3_close() 、sqlite3_create_collation()、sqlite3_collation_needed()、sqlite3_create_function()、sqlite3_finalize()、sqlite3_sqlite3_get_table()、sqlite3_reset() 、sqlite3_step() 等。
獲取錯誤的函數信息函數:sqlite3_errmsg().
聲明:const char * sqlite3_errmsg(sqlite3 *) ; 語句句柄是唯一參數,返回該鏈接上API調用產生的最近的錯誤,無錯誤才返回“not an error”.
SQLite 結果代碼:《SQLite權威指南》page195.
繁忙情況處理:sqlite3_busy_handler() , sqlite3_busy_timeout( ).注意應急計划的啟動,設置合理的超時時間。
模式改變處理:從鎖定的角度來看,模式改變的時間在sqlite3_prepare()調用和sqlite3_step()調用之間。應對的方法就是處理改變重新開始。導致SQLITE_SCHEMA存在的原因:分離數據庫、修改或者安裝用戶自定義的函數或者聚合、修改或者安裝用戶自定義的排序規則、修改或者安裝授權函數、清理數據庫空間等。這種錯誤情況與VDBE有關。
追蹤SQL:使用函數sqlite3_trace( ) .
函數聲明:void *sqlite3_trace(sqlite* , void(*xTrace)(void * , const char *) , void * );
6.操作控制
基本都是監視數據庫的連接和事務的函數。
提交鈎子:sqlite3_commit_hook()監視連接上的事務提交事件。
聲明: void * sqlite_commit_hook(sqlite * cnx , /*數據庫句柄*/
int (*xCallback )(void * data) , /*回調函數*/
void *data , /*應用程序數據*/);
回滾鈎子:sqlite3_rollback_hook()監視連接上的事務提交事件。
聲明: void * sqlite_rollback_hook(sqlite * cnx , /*數據庫句柄*/
int (*xCallback )(void * data) , /*回調函數*/
void *data , /*應用程序數據*/);
注意自動回滾無法觸發回調函數。
更新鈎子:sqlite3_update_hook()監視連接上的事務提交事件。
聲明: void * sqlite_update_hook(sqlite * cnx , /*數據庫句柄*/
int (*xCallback )(void * data) , /*回調函數*/
void *data , /*應用程序數據*/);
此時,回調函數的行式:void callback( void * data,/*更新鈎子的第三個參數*/
int operation_code,/*與sqlite_update、sqlite_insert、sqlite_delete操作對應*/
char const *db_name,char const *table_name,sqlite_int64 rowid,);
7.授權函數
事件過濾器:sqlite3_set_authorizer()
聲明: int sqlite3_set_authorizer(sqlite3 * ,int (*xAuth)(void *,int , const char * , const char * ,const char * , const char * ,) ,void *pUserData);
注意:授權函數是存在回調函數的:
int auth(void *, /*用戶數據*/
int, /*事件代碼*/
const char *, /*事件具體相關的參數*/
const char *, /*事件具體相關的參數*/
const char *, /*數據庫名稱*/
const char *, /*觸發器或者視圖名稱*/)
授權函數的返回值:SQLITE_OK、SQLITE_DENY(終止整個sql語句)、SQLITE_IGNORE。注意交互式程序的幫助。page209。
五、參考的原文:
http://www.runoob.com/sqlite/sqlite-tutorial.html
https://baike.baidu.com/item/SQLite/375020?fr=aladdin
https://blog.csdn.net/mao834099514/article/details/51680855
https://www.cnblogs.com/cchust/p/5121559.html
https://blog.csdn.net/zgrjkflmkyc/article/details/45150951
