SQLite權(quán)威指南(第二版)第六章 核心 C API

SQLite3 API 包括很多函數(shù)振愿,但是只有大概8個(gè)函數(shù)是實(shí)際處理連接毅糟、查詢红选、斷開與數(shù)據(jù)庫(kù)連接所必需的。

一留特、查詢封裝

1纠脾、連接與斷開連接

執(zhí)行SQL命令前,要先連接數(shù)據(jù)庫(kù)蜕青,也叫打開數(shù)據(jù)庫(kù)。結(jié)束時(shí)糊渊,要斷開連接右核,也叫關(guān)閉數(shù)據(jù)庫(kù)。
打開數(shù)據(jù)庫(kù)的函數(shù)有:

  • sqlite3_open_v2():推薦使用
  • sqlite3_open()
  • sqlite3_open16()
int sqlite3_open_v2(
    const char *filename,    /*數(shù)據(jù)庫(kù)文件名*/
    sqlite3 **ppDb           /*OUT:SQLite數(shù)據(jù)庫(kù)句柄*/
    int flags,               /*標(biāo)志*/
    const char *zVfs         /*要使用的VFS模塊的名稱*/
)

說(shuō)明:

  1. filename:可以為操作系統(tǒng)文件渺绒、文本字符串‘memory’贺喝、空字符串。filename為‘memory’時(shí)宗兼,表示將在內(nèi)存中創(chuàng)建數(shù)據(jù)庫(kù)躏鱼;為空字符串或null時(shí),表示打開臨時(shí)磁盤文件殷绍,并在連接關(guān)閉時(shí)自動(dòng)刪除文件染苛。為其他選項(xiàng)時(shí),嘗試打開參數(shù)指定的文件主到,若文件不存在且flags不等于SQLITE_OPEN_CREATE茶行,則返回錯(cuò)誤。
  2. ppDb:在打開完成后登钥,sqlite3_open_v2會(huì)初始化sqlite3結(jié)構(gòu)體傳遞給ppDb參數(shù)畔师,是事務(wù)上下文環(huán)境。代表一個(gè)連接句柄牧牢,而不是一個(gè)數(shù)據(jù)庫(kù)句柄看锉,因?yàn)榭赡軙?huì)附加多個(gè)數(shù)據(jù)庫(kù)到一個(gè)連接上姿锭。
  3. flags:是一個(gè)比特向量,包括以下幾種值:SQLite_OPEN_READONLY伯铣、SQLite_OPEN_READWRITE呻此、SQLITE_OPEN_CREATE等。SQLite_OPEN_READONLY懂傀、SQLite_OPEN_READWRITE分別表示只讀和讀/寫模式打開數(shù)據(jù)庫(kù)趾诗,若文件不存在,就返回錯(cuò)誤蹬蚁。
  4. zVfs:表示允許調(diào)用者覆寫默認(rèn)的sqlite3_vfs操作系統(tǒng)接口恃泪。

關(guān)閉連接的函數(shù):

int sqlite3_close(sqlite3*);

說(shuō)明:

  • sqlite3_close要成功執(zhí)行,須完成連接中所有的查詢犀斋。若有一個(gè)未完成贝乎,就會(huì)返回SQLITE_BUSY,并顯示錯(cuò)誤消息叽粹。
  • sqlite3_close關(guān)閉連接時(shí)览效,若連接上有打開的事務(wù),該事務(wù)將自動(dòng)回滾虫几。

2锤灿、執(zhí)行查詢

執(zhí)行SQL命令的函數(shù):

int sqlite3_exec(
    sqlite3*,                            /*打開的數(shù)據(jù)庫(kù)*/
    const char *sql,                           /*要執(zhí)行的SQL*/
    sqlite_callback,                           /*回調(diào)函數(shù)*/
    void *data                           /*回調(diào)函數(shù)的第一個(gè)參數(shù)*/
    char **errmsg                           /*錯(cuò)誤信息*/
);

說(shuō)明:

  • sqlite3_exec()解析執(zhí)行sql語(yǔ)句中的每個(gè)命令,知道遇到該字符串的末尾或遇到錯(cuò)誤辆脸。
  • sqlite3_exec()提供了獲取select語(yǔ)句結(jié)果的回調(diào)機(jī)制但校。
  • sqlite_callback:回調(diào)函數(shù)的指針,調(diào)用函數(shù)會(huì)處理每個(gè)sql語(yǔ)句中執(zhí)行的select語(yǔ)句的結(jié)果啡氢。

sqlite_callback回調(diào)函數(shù)的聲明:

typedef int (*sqlite3_callback)(
    void*,            /*該參數(shù)就是sqlite3_exec的第四個(gè)參數(shù)提供的數(shù)據(jù)*/
    int,              /*行中字段的數(shù)目*/
    char**,           /*代表行中字段名稱的字符串?dāng)?shù)組*/
    char**            /*代表字段名稱的字符串?dāng)?shù)組*/
)

說(shuō)明:

  • sqlite3_callback回調(diào)函數(shù)的返回值状囱,會(huì)影響sqlite3_exec()的執(zhí)行。若返回非零值倘是,sqlite3_exec()將會(huì)終止亭枷。

3、獲取表查詢

函數(shù)聲明如下:

int sqlite3_get_table(
    sqlite3*,                /*打開的數(shù)據(jù)庫(kù)*/
    const char *sql,         /*要執(zhí)行的SQL語(yǔ)句*/
    char ***resultp,         /*結(jié)果寫入該指針指向的char*[]*/
    int *nrow,               /*結(jié)果集中行的數(shù)目*/
    int *ncolumn,            /*結(jié)果集中字段的數(shù)目*/
    char **errmsg            /*錯(cuò)誤信息*/
)

說(shuō)明:

  • resultp:堆上聲明的內(nèi)存搀崭,將返回的記錄都存儲(chǔ)在resultp中叨粘,必須使用sqlite3_free_table()釋放內(nèi)存。
  • resultp的前幾個(gè)元素實(shí)際上不是真的記錄门坷,而是結(jié)果集中的列名稱宣鄙。

二、查詢準(zhǔn)備

相比于sqlite3_exec()和sqlite3_get_table()默蚌,準(zhǔn)備查詢提供了更多的功能冻晤,更好的控制和更多的信息。
實(shí)際上绸吸,sqlite3_exec()更適合運(yùn)行修改數(shù)據(jù)庫(kù)的命令(create鼻弧、drop设江、insert、update攘轩、delete)叉存。而準(zhǔn)備查詢更適合select語(yǔ)句,因?yàn)樗梢蕴峁└嗟男畔⒍劝铮⑶铱梢酝ㄟ^游標(biāo)來(lái)遍歷結(jié)果集歼捏。
下面就準(zhǔn)備查詢的整個(gè)過程及三個(gè)步驟:編譯、執(zhí)行笨篷、完成來(lái)進(jìn)行詳細(xì)解釋瞳秽。

1、編譯

編譯或者準(zhǔn)備一個(gè)SQL語(yǔ)句率翅,就是把它編譯為虛擬數(shù)據(jù)庫(kù)引擎(VDBE)可讀的字節(jié)碼练俐。
對(duì)應(yīng)的函數(shù)聲明為:

int sqlite3_prepare_v2(
    sqlite3 *db,                    /*數(shù)據(jù)庫(kù)句柄*/
    const char *zSql,               /*SQL文本,UTF-8編碼的*/
    int nBytes,                     /*zSql的字節(jié)長(zhǎng)度*/
    sqlite3_stmt **ppStmt,          /*輸出:語(yǔ)句句柄*/
    const char **pzTail             /*輸出:指向zSql未使用部分的指針*/
)

說(shuō)明:

  1. sqlite3_prepare_v2() 只編譯zSql字符串中的第一個(gè)SQL語(yǔ)句(zSql字符串中可能包含多個(gè)SQL語(yǔ)句)冕臭。
  2. 然后分配這個(gè)語(yǔ)句執(zhí)行時(shí)所需的所有資源腺晾,并將其字節(jié)碼關(guān)聯(lián)到這個(gè)語(yǔ)句的句柄(也就是ppStmt參數(shù)指定的語(yǔ)句句柄)。
  3. ppStmt:語(yǔ)句的句柄ppStmt 依賴于所編譯的數(shù)據(jù)庫(kù)模式辜贵。如果在準(zhǔn)備或執(zhí)行語(yǔ)句期間悯蝉,模式改變,sqlite3_prepare_v2() 會(huì)自動(dòng)重新編譯語(yǔ)句托慨。若重新編譯失敗泉粉,就會(huì)在sqlite3_step()調(diào)用時(shí)返回SQLITE_SCHEMA錯(cuò)誤。
  4. pzTail:在調(diào)用sqlite3_prepare()后榴芳,pzTail會(huì)指向zSql字符串中的下一條語(yǔ)句的起始位置。使用pzTail跺撼,會(huì)使執(zhí)行一批SQL命令變得更容易窟感。

2、執(zhí)行

準(zhǔn)備就緒后歉井,下一步就是執(zhí)行sqlite3_step()柿祈,
聲明如下:

int sqlite3_step(sqlite3_stmt *pStmt);

說(shuō)明:

  • sqlite3_step()接收的參數(shù)是sqlite3_prepare_v2()輸出的參數(shù)ppStmt。
  • sqlite3_step()直接與VDBE通信哩至,執(zhí)行一個(gè)又一個(gè)字節(jié)碼指令來(lái)執(zhí)行SQL語(yǔ)句躏嚎。
  • 在第一次調(diào)用sqlite3_step()時(shí),VDBE會(huì)獲取執(zhí)行命令所需的數(shù)據(jù)庫(kù)鎖菩貌。
  • 對(duì)于不返回?cái)?shù)據(jù)的SQL語(yǔ)句卢佣,第一次sqlite3_step()后就執(zhí)行完SQL語(yǔ)句了,并返回一個(gè)指示結(jié)果的代碼箭阶。
  • 對(duì)于返回?cái)?shù)據(jù)的SQL語(yǔ)句虚茶,如select語(yǔ)句戈鲁,第一次調(diào)用sqlite3_step()后,將語(yǔ)句定位在第一個(gè)記錄的B-tree游標(biāo)上嘹叫,后續(xù)調(diào)用sqlite3_step()會(huì)一次將光標(biāo)定位在結(jié)果集內(nèi)的后續(xù)記錄上婆殿,并返回SQLITE_ROW,直到返回SQLITE_DONE罩扇,表示游標(biāo)已到達(dá)結(jié)果集末尾婆芦。

3、完成與重置

語(yǔ)句執(zhí)行結(jié)束后喂饥,必須終止消约。可使用下面函數(shù)之一:

int sqlite3_finalize(sqlite3_stmt *pStmt);
int sqlite3_reset(sqlite3_stmt *pStmt);

說(shuō)明:

  • sqlite3_finalize():關(guān)閉語(yǔ)句仰泻,釋放資源荆陆,提交或回滾任何隱式事務(wù),清除日志文件并釋放相關(guān)聯(lián)的鎖集侯。
  • 若要重復(fù)使用語(yǔ)句被啼,可使用sqlite3_reset()。與sqlite3_finalize的差別在于棠枉,sqlite3_reset會(huì)保留與語(yǔ)句關(guān)聯(lián)的資源浓体,以便重新執(zhí)行,而不用再次調(diào)用sqlite3_prepare()來(lái)編譯SQL命令辈讶。

sqlite_complete():尋找字符串中的終止符:分號(hào)命浴。

三、獲取記錄

準(zhǔn)備查詢提供了獲取記錄信息的更多選擇贱除。
獲取結(jié)果集中的字段數(shù)生闲,函數(shù)聲明如下:

int sqlite3_column_count(sqlite_stmt *pStmt);
int sqlite3_data_count(sqlite3_stmt *pStmt);

說(shuō)明:

  • sqlite3_column_count():返回與語(yǔ)句句柄關(guān)聯(lián)的字段數(shù)量;若語(yǔ)句不是select語(yǔ)句月幌,則返回0碍讯。
  • 在sqlite3_step()返回SQLITE_ROW時(shí),返回當(dāng)前記錄的列數(shù)扯躺。只有語(yǔ)句句柄有有效的游標(biāo)時(shí)捉兴,才可以正常工作。

1录语、獲取列(字段)信息

獲取當(dāng)前記錄每一列的列名稱倍啥,函數(shù)聲明如下:

cont char *sqlite3_column_name(
    sqlite3_stmt*,                    /*語(yǔ)句句柄*/
    int iCol                          /*列的順序*/
)

獲取每個(gè)列的存儲(chǔ)類,函數(shù)聲明如下:

int sqlite3_column_type(
    sqlite3_stmt*,                    /*語(yǔ)句句柄*/
    int iCol                          /*列的順序*/
)

說(shuō)明:該函數(shù)返回五個(gè)存儲(chǔ)類對(duì)應(yīng)的整數(shù)值:

  • #define SQLITE_INTEGER 1
  • #define SQLITE_FLOAT 2
  • #define SQLITE_TEXT 3
  • #define SQLITE_BLOB 4
  • #define SQLITE_NULL 5

獲取每個(gè)列聲明的數(shù)據(jù)類型澎埠,函數(shù)聲明如下:

const char *sqlite3_column_decltype(
    sqlite3_stmt*,                    /*語(yǔ)句句柄*/
    int iCol                          /*列的順序*/
)

說(shuō)明:

  • 如果結(jié)果集中的列與實(shí)際表中的列不對(duì)應(yīng)(不對(duì)應(yīng)的例子如虽缕,結(jié)果集中的列是要返回一個(gè)文本值、表達(dá)式失暂、函數(shù)彼宠、聚合結(jié)果等鳄虱,而不是實(shí)際表中的列),那么這個(gè)函數(shù)就會(huì)返回其聲明類型為NULL凭峡。

獲得某一列的其他信息

const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int iCol);
const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int iCol);
const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int iCol);

說(shuō)明:

  • sqlite3_column_database_name:返回與這個(gè)列相關(guān)的數(shù)據(jù)庫(kù)
  • sqlite3_column_table_name:返回與這個(gè)列相關(guān)的表
  • sqlite3_column_origin_name:返回在schema中定義的實(shí)際名稱(別名等)
  • 這些函數(shù)只有在編譯SQLITE時(shí)拙已,啟用了SQLITE_ENABLE_COLUMN_METADATA預(yù)處理命令時(shí)才能用。

2摧冀、獲取列(字段)值

獲取當(dāng)前記錄每列的值:

xxx sqlite3_column_xxx(
    sqlite3_stmt*,              /*語(yǔ)句句柄*/
    int iCol                    /*列的順序*/
)

說(shuō)明:

  • 該函數(shù)會(huì)按按照期望的數(shù)據(jù)類型返回列的值:
int sqlite3_column_int(sqlite3_stmt*, int iCol);
double sqlite3_column_double(sqlite3_stmt*, int iCol);
long long int sqlite3_column_int64(sqlite3_stmt*, int iCol);
const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);

SQLite會(huì)將內(nèi)部數(shù)據(jù)類型表示形式轉(zhuǎn)換為所請(qǐng)求的類型:

內(nèi)部類型 請(qǐng)求類型 轉(zhuǎn)換
NULL INTEGER 0
NULL FLOAT 0.0
NULL TEXT NULL
NULL BLOB NULL
INTEGER FLOAT 整型轉(zhuǎn)浮點(diǎn)型
INTEGER TEXT 整數(shù)的ASCII描述
INTEGER BLOB 整數(shù)的ASCII描述
FLOAT INTEGER 浮點(diǎn)型轉(zhuǎn)整型
FLOAT TEXT 浮點(diǎn)數(shù)的ASCII描述
FLOAT BLOB 浮點(diǎn)數(shù)的ASCII描述
TEXT INTEGER 使用atoi()
TEXT FLOAT 使用atoi()
TEXT BLOB 無(wú)變化
BLOB INTEGER 先轉(zhuǎn)成文本倍踪,再使用atoi()
BLOB FLOAT 先轉(zhuǎn)成文本,再使用atoi()
BLOB TEXT 需要時(shí)加上\0000終結(jié)符

獲取實(shí)際數(shù)據(jù)的長(zhǎng)度索昂,聲明如下

int sqlite3_column_bytes(
    sqlite3_stmt*,              /*語(yǔ)句句柄*/
    int iCol                    /*列的順序*/
)

說(shuō)明:

  • 獲取到長(zhǎng)度以后就可以使用sqlite3_column_blob()復(fù)制二進(jìn)制數(shù)據(jù)建车。

獲取連接句柄

int sqlite3_db_handle(sqlite3_stmt*);

說(shuō)明:

  • sqlite3_errmsg()需要用到連接句柄

四、參數(shù)化查詢

1椒惨、默認(rèn)的參數(shù)順序

API支持在SQL語(yǔ)句中指定參數(shù)缤至,允許在后面為參數(shù)提供或綁定值。
參數(shù)化語(yǔ)句如下:

insert into episodes (id, name) values (?, ?)

說(shuō)明:

  1. sqlite3_prepare()識(shí)別到SQL語(yǔ)句中有參數(shù)康谆。內(nèi)部领斥,為每個(gè)參數(shù)分配一個(gè)編號(hào)來(lái)唯一標(biāo)識(shí)參數(shù)。
  2. 然后期望在執(zhí)行前沃暗,對(duì)給定的參數(shù)綁定特定的值月洛。
  3. 若沒有綁定值給參數(shù),sqlite3_step()會(huì)使用null來(lái)代替孽锥。

綁定參數(shù)值的函數(shù)聲明如下:

sqlite3_bind_xxx(
    sqlite3_stmt*,             /*語(yǔ)句句柄*/
    int i,                           /*參數(shù)編號(hào)*/
    xxx value                  /*要綁定的值*/
)

常用綁定函數(shù)如下:

int sqlite3_bind_int(sqlite3_stmt*, int, int);
int sqlite3_bind_double(sqlite3_stmt*, int, double);
int sqlite3_bind_int64(sqlite3_stmt*, int, long long int);
int sqlite3_bind_null(sqlite3_stmt*, int);
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int n, void(*)(void*));

說(shuō)明:

  • 綁定函數(shù)分為兩類嚼黔,一類是標(biāo)量值(int, double, int64, 和 NULL),一類是數(shù)組(blob, text, 和 text16)
  • 標(biāo)量值綁定和數(shù)組綁定的區(qū)別在于惜辑,后者需要一個(gè)長(zhǎng)度參數(shù)和一個(gè)指向清理函數(shù)的指針唬涧。
  • sqlite3_bind_text()會(huì)自動(dòng)轉(zhuǎn)義引號(hào)字符

使用BLOB數(shù)組綁定函數(shù),聲明如下:

int sqlite3_bind_blob( 
    sqlite3_stmt*,         /* 語(yǔ)句句柄 */
    int,                   /* 順序 */
    const void*,           /* 指向blob數(shù)據(jù)的指針 */
    int n,                 /* 數(shù)據(jù)的字節(jié)長(zhǎng)度 */
    void(*)(void*)         /* 清理處理程序 */
); 

說(shuō)明:
最后一個(gè)參數(shù)盛撑,也就是清理句柄
(1)有兩個(gè)預(yù)定義的值爵卒,定義如下:

#define     SQLITE_STATIC       ((void(*)(void *))0)
#define     SQLITE_TRANSIENT       ((void(*)(void *))-1)
  • SQLITE_STATIC:告訴數(shù)組綁定函數(shù),數(shù)組內(nèi)存駐留在非托管的控件撵彻,SQLite不會(huì)試圖清理該控件
  • SQLITE_TRANSIENT告訴綁定數(shù)組,數(shù)組內(nèi)存常有變化实牡,SQLite需要使用自己的數(shù)據(jù)副本陌僵,該副本在語(yǔ)句終止時(shí)會(huì)自動(dòng)清除。

(2)還有一個(gè)指向自己的清理函數(shù)的指針创坞,函數(shù)形式如下:

void cleanup_fn(void*)

語(yǔ)句結(jié)束時(shí)碗短,SQLite會(huì)調(diào)用該清理函數(shù),并將數(shù)組內(nèi)存?zhèn)魅搿?/p>

2题涨、參數(shù)編號(hào)

給參數(shù)編號(hào)偎谁,而不是使用內(nèi)部序列編號(hào)总滩。參數(shù)編號(hào)的語(yǔ)法是問號(hào)后緊跟一個(gè)數(shù)字。
參考例子:

insert into episodes (id, cid, name) values (?100,?100,?101)";

說(shuō)明:

  • 參數(shù)編號(hào)100使用兩次巡雨,表示需要將值綁定到多個(gè)地方闰渔,這樣可以節(jié)省時(shí)間。
  • 參數(shù)編號(hào)的范圍是整數(shù)值1~999铐望。盡量選擇較小的數(shù)字

3冈涧、參數(shù)命名

給參數(shù)命名,在指定參數(shù)編號(hào)的地方指定一個(gè)名稱正蛙。
區(qū)別在于督弓,參數(shù)編號(hào)的語(yǔ)法是個(gè)問號(hào)?前綴乒验,而參數(shù)命名的前綴是一個(gè)冒號(hào)或者@符號(hào)愚隧。
示例如下:

insert into episodes (id, cid, name) values (:cosmo,:cosmo,@newman)

4、Tcl參數(shù)

基本與參數(shù)命名完全相同锻全,只是Tcl參數(shù)使用一些變量作為參數(shù)名稱狂塘。
Tcl參數(shù)語(yǔ)法,與命名參數(shù)的區(qū)別在于虱痕,不是前面的參數(shù)加上冒號(hào)(:)或@符號(hào)睹耐,而是使用美元符號(hào)($)。

五部翘、錯(cuò)誤與異常

一定要在代碼中關(guān)注的情況:

  • 錯(cuò)誤
  • 繁忙情況
  • 模式更改

1硝训、錯(cuò)誤處理

API函數(shù),會(huì)返回整數(shù)結(jié)果碼新思,這些結(jié)果碼表示返回某種類型的錯(cuò)誤代碼窖梁。編程時(shí),必須確保處理了各種可能的錯(cuò)誤情況夹囚。
可以返回結(jié)果碼的函數(shù)有:

  • sqlite3_bind_xxx()
  • sqlite3_close()
  • sqlite3_create_collation()
  • sqlite3_collation_needed()
  • sqlite3_create_function()
  • sqlite3_prepare_v2() *
  • sqlite3_exec() *
  • sqlite3_finalize()
  • sqlite3_get_table()
  • sqlite3_open_v2() *
  • sqlite3_reset()
  • sqlite3_step()
    說(shuō)明:標(biāo)*的是常見的需要關(guān)注返回結(jié)果碼的函數(shù)

可以使用sqlite3_errmsg()獲取給定的錯(cuò)誤的詳細(xì)信息纵刘,聲明如下:

const char *sqlite3_errmsg(sqlite3*);

說(shuō)明:

  • 參數(shù)為連接句柄。
  • 返回連接上API調(diào)用產(chǎn)生的最近的錯(cuò)誤荸哟。
  • 沒有錯(cuò)誤假哎,返回“not an error”.


    1.png

2、繁忙情況處理

當(dāng)調(diào)用需要獲取鎖的API鞍历,但是SQLite無(wú)法得到鎖時(shí)舵抹,會(huì)返回SQLITE_BUSY。
處理這種情況的方法有三種:

  • 通過重新運(yùn)行該語(yǔ)句劣砍,或者采取一些其他操作來(lái)自己處理SQLITE_BUSY惧蛹;
  • 讓SQLite調(diào)用繁忙處理程序;
  • 讓SQLite等待(阻塞或睡眠)一段時(shí)間來(lái)等待鎖解除。

2.1香嗓、用戶自定義的繁忙處理

函數(shù)聲明如下:

int sqlite3_busy_handler(
    sqlite3*, 
    int(*)(void*,int), 
    void*
);

說(shuō)明:

  • 第二個(gè)參數(shù):指向繁忙處理函數(shù)的函數(shù)指針迅腔。而繁忙處理函數(shù)的第二個(gè)參數(shù)是事先想同一個(gè)鎖事件的處理程序的調(diào)用次數(shù)。
  • 第三個(gè)參數(shù):指向應(yīng)用程序特定數(shù)據(jù)的指針靠娱,會(huì)作為繁忙處理函數(shù)的第一個(gè)參數(shù)沧烈。
  • 繁忙處理函數(shù)并不一定保證被調(diào)用,如果sqlite檢測(cè)到可能產(chǎn)生死鎖饱岸,就會(huì)放棄調(diào)用繁忙處理程序掺出。
  • 唯一局限:繁忙處理程序可能不會(huì)關(guān)閉數(shù)據(jù)庫(kù)。因?yàn)槿绻P(guān)閉數(shù)據(jù)庫(kù)苫费,會(huì)刪除外面的執(zhí)行查詢的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)汤锨,并導(dǎo)致程序崩潰。

3百框、模式改變處理

在sqlite3_prepare()和sqlite3_step()之間闲礼,發(fā)生模式更改發(fā)生了。
這種情況發(fā)生時(shí)铐维,唯一應(yīng)對(duì)的方法是處理改變柬泽,并重新開始。因?yàn)橐丫幾g的VDBE可能會(huì)指向一個(gè)已經(jīng)不存在的或者位置發(fā)生改變的數(shù)據(jù)庫(kù)對(duì)象嫁蛇。

可能會(huì)導(dǎo)致SQLITE_SCHEMA錯(cuò)誤:

  • 分離數(shù)據(jù)庫(kù)锨并;
  • 修改或安裝用戶自定義的函數(shù)或聚合;
  • 修改或安裝用戶自定義的排序規(guī)則睬棚;
  • 修改或安裝授權(quán)函數(shù)第煮;
  • 清理數(shù)據(jù)庫(kù)空間;

跟蹤SQL語(yǔ)句執(zhí)行的操作:

void *sqlite3_trace(
    sqlite3*, 
    void(*xTrace)(void*,const char*), 
    void*
);

六抑党、操作控制

API提供一些函數(shù)包警,在編譯或運(yùn)行時(shí)監(jiān)視或管理SQL命令。

1底靠、提交鉤子

監(jiān)視給定連接上的事務(wù)提交事件害晦,聲明如下:

void *sqlite3_commit_hook( 
    sqlite3 *cnx,                         /* 數(shù)據(jù)庫(kù)句柄 */
    int(*xCallback)(void *data),          /* 回調(diào)函數(shù) */
    void *data                            /* 應(yīng)用程序數(shù)據(jù) */
); 

說(shuō)明:

  • 當(dāng)連接cnx上發(fā)生提交事務(wù)時(shí),觸發(fā)xCallback回調(diào)函數(shù)暑中;
  • data為回調(diào)函數(shù)xCallback的參數(shù)
  • 如果xCallback返回非零值壹瘟,提交將轉(zhuǎn)為回滾
  • xCallback中傳入NULL,會(huì)禁用當(dāng)前注冊(cè)函數(shù)鳄逾;
  • 一個(gè)連接只能注冊(cè)一個(gè)回調(diào)函數(shù)俐筋,如果沒有注冊(cè)過,sqlite3_commit_hook會(huì)返回NULL严衬。如果以前注冊(cè)過,會(huì)返回以前參數(shù)data值笆呆。

2请琳、回滾鉤子

監(jiān)視給定連接上的回滾事件粱挡,聲明如下:

void *sqlite3_rollback_hook(
    sqlite3 *cnx, 
    void(*xCallback)(void *data), 
    void *data
);

3、更新鉤子

監(jiān)視給定連接上的所有更新俄精、插入询筏、刪除操作,聲明如下:

void *sqlite3_update_hook(
    sqlite3 *cnx,
    void(*)(void *, int, char const*, char const*, sqlite_int64),
    void *data
);

其中第二個(gè)參數(shù)竖慧,也就是回調(diào)函數(shù)的聲明如下:

void callback ( 
    void * data,
    int operation_code,
    char const *db_name,
    char const *table_name,
    sqlite_int64 rowid
),

說(shuō)明:

  • data為sqlite3_update_hook的第三個(gè)參數(shù)嫌套;
  • operation_code:代表插入、更新圾旨、刪除操作踱讨;
  • db_name和table_name分別代表數(shù)據(jù)庫(kù)名和表名;
  • rowid為受影響的行砍的;
  • 系統(tǒng)表上的操作不會(huì)調(diào)用回調(diào)函數(shù)痹筛。

4、授權(quán)函數(shù)

監(jiān)控或控制查詢語(yǔ)句的編譯廓鞠,提供了一種限制某種SQL操作或否決對(duì)數(shù)據(jù)庫(kù)中特定表或字段訪問的方法:

int sqlite3_set_authorizer(
    sqlite3*,
    int (*xAuth)( void*,int,
    const char*, const char*,
    const char*,const char*),
    void *pUserData
);

授權(quán)函數(shù)的形式如下:

int auth( 
    void*, /* user data */
    int, /* event code */
    const char*, /* event specific */
    const char*, /* event specific */
    const char*, /* database name */
    const char* /* trigger or view name */ 
);

auth各參數(shù)的說(shuō)明:

  • 第一個(gè)參數(shù)帚稠,是sqlite3_set_authorizer的第一個(gè)參數(shù)傳來(lái)的
  • 第二個(gè)參數(shù),是表6-3中的某個(gè)常量床佳,代表授予的操作權(quán)限的類型
  • 第三滋早、四個(gè)參數(shù),是具體的事件代碼砌们,在表6-2中
  • 第五個(gè)參數(shù)杆麸,是數(shù)據(jù)庫(kù)名稱
  • 第六個(gè)參數(shù),是負(fù)責(zé)訪問嘗試的最內(nèi)層的觸發(fā)器或視圖怨绣。為null角溃,代表訪問直接來(lái)自頂級(jí)的SQL語(yǔ)句。
  • 返回值為SQLITE_OK篮撑、SQLITE_DENY,减细、 SQLITE_IGNORE中的一個(gè)。


    2.png

終止給定連接上的懸掛數(shù)據(jù)庫(kù)操作:

void sqlite3_interrupt(
    sqlite3* /* 連接句柄 */
);

按組合鍵Ctrl+C時(shí)會(huì)調(diào)用這個(gè)函數(shù)

讓應(yīng)用程序在長(zhǎng)時(shí)間運(yùn)行的查詢過程中為用戶提供反饋信息:

void sqlite3_progress_handler( 
    sqlite3*,          /* 連接句柄 */
    int frq,           /* 調(diào)用頻率 */
    int(*)(void*),     /* 回調(diào)函數(shù) */
    void*              /* 應(yīng)用程序數(shù)據(jù) */
); 

七赢笨、線程

1未蝌、共享緩存模型

  • 允許一個(gè)進(jìn)程中的多個(gè)連接使用共同的緩存和不同的并發(fā)模型。
  • 這個(gè)圖是為嵌入式服務(wù)器設(shè)計(jì)的茧妒,這個(gè)服務(wù)器中的單線程可以代表其他多個(gè)線程有效的管理多個(gè)數(shù)據(jù)庫(kù)連接萧吠。
  • 線程向服務(wù)器中發(fā)送SQL語(yǔ)句,服務(wù)器使用分配給該線程的連接來(lái)執(zhí)行桐筏,并把結(jié)果回傳給線程纸型。
  • 線程可以發(fā)起命令,控制自己的事務(wù),只是其實(shí)際的連接狰腌,存在于另一個(gè)線程(服務(wù)器線程)中除破,被服務(wù)器線程管理著。
  • 共享緩存模式使用表鎖琼腔,分別保持讀連接和寫連接瑰枫。表鎖只存在于共享緩存下的連接。


    3.png

共享緩存模式中的連接使用的不同并發(fā)模型和隔離級(jí)別:

  1. 讀提交隔離級(jí)別:連接不可以想已有讀鎖連接的表中寫入丹莲。
  2. 讀未提交隔離級(jí)別:連接不會(huì)在讀取的表上加讀鎖光坝,因此寫操作可以在連接讀取時(shí)修改表。
  3. 解鎖通知:

2甥材、線程和內(nèi)存管理

與線程和內(nèi)存管理相關(guān)聯(lián)的函數(shù):

void sqlite3_soft_heap_limit(int N);
int sqlite3_release_memory(int N);

說(shuō)明:

  • sqlite3_soft_heap_limit:將調(diào)用線程的當(dāng)前軟堆設(shè)置為N字節(jié)
  • sqlite3_release_memory:當(dāng)使用中線程的堆超過N字節(jié)時(shí)盯另,會(huì)調(diào)用sqlite3_release_memory。返回值為實(shí)際釋放的字節(jié)數(shù)擂达。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末土铺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子板鬓,更是在濱河造成了極大的恐慌悲敷,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件俭令,死亡現(xiàn)場(chǎng)離奇詭異后德,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)抄腔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門瓢湃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人赫蛇,你說(shuō)我怎么就攤上這事绵患。” “怎么了悟耘?”我有些...
    開封第一講書人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵落蝙,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我暂幼,道長(zhǎng)筏勒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任旺嬉,我火速辦了婚禮管行,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘邪媳。我一直安慰自己捐顷,他們只是感情好荡陷,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著迅涮,像睡著了一般亲善。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上逗柴,一...
    開封第一講書人閱讀 50,050評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音顿肺,去河邊找鬼戏溺。 笑死,一個(gè)胖子當(dāng)著我的面吹牛屠尊,可吹牛的內(nèi)容都是我干的旷祸。 我是一名探鬼主播,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼讼昆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼托享!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起浸赫,我...
    開封第一講書人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤闰围,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后既峡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體羡榴,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年运敢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了校仑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡传惠,死狀恐怖迄沫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情卦方,我是刑警寧澤羊瘩,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站愿汰,受9級(jí)特大地震影響困后,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜衬廷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一摇予、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吗跋,春花似錦侧戴、人聲如沸宁昭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)积仗。三九已至,卻和暖如春蜕猫,著一層夾襖步出監(jiān)牢的瞬間寂曹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工回右, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留隆圆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓翔烁,卻偏偏與公主長(zhǎng)得像渺氧,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蹬屹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容