一、查询参数化
总体而言,绑定函数可分为两类,一类用于标量值(int、double、int64、NULL),另一类用于数组(blob、text和text16)。其中,数组绑定函数需要一个长度参数和指向清理函数的指针。
sqlite3_bind_text()自动转义引号字符。
使用BLOB类型时,绑定函数声明如下:
1 /* 2 ** Bind a blob value to an SQL statement variable. 3 */ 4 int sqlite3_bind_blob( 5 sqlite3_stmt *pStmt, /*语句句柄*/ 6 int i, /*次序*/ 7 const void *zData, /*指向blob数据*/ 8 int nData, /*数据的字节长度*/ 9 void (*xDel)(void*) /*清理处理程序*/10 )
对于xDel参数,有两个特殊含义的预定义值。
1 typedef void (*sqlite3_destructor_type)(void*);2 #define SQLITE_STATIC ((sqlite3_destructor_type)0)3 #define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1)
- SQLITE_STATIC:告诉绑定函数数组内存驻留在非托管的空间,SQLite不会视图清理该空间。
- SQLITE_TRANSIENT:告诉绑定函数数组内存经常变化,SQLite需要使用自己的数据副本,此副本在语句终结时自动清除。
- 也可提供一个指向自定义的清理函数指针,语句结束时会被自动调用。该函数形式如下:
void cleanup_fn(void*)
1、参数编号
允许为参数指定编号,可设置参数范围1~999。
如下代码,分别指定了100和101位参数的编号。其中参数编号100使用两次,这样可以节省时间。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 name = "Mackinaw Peaches"; 2 sql = "insert into episodes (id, cid, name) " 3 "values (?100,?100,?101)"; 4 5 rc = sqlite3_prepare(db, sql, (int)strlen(sql), &stmt, &tail); 6 7 if(rc != SQLITE_OK) { 8 fprintf(stderr, "sqlite3_prepare() : Error: %s\n", tail); 9 return rc;10 }11 12 sqlite3_bind_int(stmt, 100, 10);13 sqlite3_bind_text(stmt, 101, name, (int)strlen(name), SQLITE_TRANSIENT);14 sqlite3_step(stmt);15 sqlite3_finalize(stmt);
2、参数命名
允许给参数命名,可在指定参数编号的地方指定一个名称。可使用:或者@。参看示例代码。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 name = "Mackinaw Peaches"; 2 sql = "insert into episodes (id, cid, name) values (:cosmo,:cosmo,:newman)"; 3 4 rc = sqlite3_prepare(db, sql, (int)strlen(sql), &stmt, &tail); 5 6 if(rc != SQLITE_OK) { 7 fprintf(stderr, "Error: %s\n", tail); 8 return rc; 9 }10 11 sqlite3_bind_int( stmt, 12 sqlite3_bind_parameter_index(stmt, ":cosmo"), 10);13 14 sqlite3_bind_text( stmt, 15 sqlite3_bind_parameter_index(stmt, ":newman"), 16 name, 17 (int)strlen(name), cleanup_fn );18 19 sqlite3_step(stmt);20 sqlite3_finalize(stmt);
与位置参数类似,sqlit3_prepare()也会为命名的参数自动分配序号。可通过sqlite_bind_parameter_index()获得编号。
1 /* 2 ** CAPI3REF: Index Of A Parameter With A Given Name 3 ** METHOD: sqlite3_stmt 4 ** 5 ** ^Return the index of an SQL parameter given its name. ^The 6 ** index value returned is suitable for use as the second 7 ** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero 8 ** is returned if no matching parameter is found. ^The parameter 9 ** name must be given in UTF-8 even if the original statement10 ** was prepared from UTF-16 text using [sqlite3_prepare16_v2()] or11 ** [sqlite3_prepare16_v3()].12 **13 ** See also: [sqlite3_bind_blob|sqlite3_bind()],14 ** [sqlite3_bind_parameter_count()], and15 ** [sqlite3_bind_parameter_name()].16 */17 SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
3、Tcl参数
属于Tcl的特定扩展。
二、错误与异常
1、错误处理
通过如下函数获取给定错误的详细信息,若无错误,将返回”not an error“。
1 /*2 ** Return UTF-8 encoded English language explanation of the most recent3 ** error.4 */5 const char *sqlite3_errmsg(sqlite3 *db)
2、繁忙情况处理
1)通过重新运行该语句或采取一些其他操作处理SQLITE_BUSY
2)让SQLite调用繁忙处理程序
该函数提供了调用用户定义函数的方法,而不是立即去阻塞或返回SQLITE_BUSY。该函数提供了繁忙处理函数的第一 个参数,繁忙处理程序的第二个参数是事先向同一个锁事件的处理程序的调用次数。
死锁不会可能不会调用此函数。
SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*);
3)让SQLite调用繁忙处理程序
涉及到sqlite3_busy_timeout()函数。该函数说明了在SQLITE_BUSY前需要等待多长锁清除时间。即使设置足够的时间(30s),仍有必要处理SQLITE_BUSY应急计划。
该函数封装了sqlite3_busy_handler()函数。
int sqlite3_busy_timeout(sqlite3 *db, int ms)
3、模式改变处理
模式更改发生的时间介于编译语句sqlit3_prepare()的调用和执行语句sqlite3_step()的调用之间。此时更改之前发生编译的准备语句将失效。sqlite3_step()调用将尝试重新编译相关的SQL并尽可能正常运行,如果无法重新编译,sqlite3_step()将返回错误码SQLITE_SCHEMA。
以下操作可能会导致SQLITE_SCHEMA错误:
- 分离数据库
- 修改或安装用户自定义的函数或聚合
- 修改或安装用户自定义的排序规则
- 修改或安装授权函数
- 清理数据库空间
处理的每个SQL语句都将传递给第二个参数中指定的回调函数。pArg参数是xTrace的第一个参数。
void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg)
三、操作控制
SQLite提供了可以在编译和运行时检视或管理SQL命令的API。这些函数可以安装用来检视数据库的回调函数,通常在各种数据库事件发生时控制这些事件。
1、提交钩子
该函数可检视给定连接上的事务提交事件。函数原型如下:
1 /* 2 ** Register a function to be invoked when a transaction commits. 3 ** If the invoked function returns non-zero, then the commit becomes a 4 ** rollback. 5 */ 6 void *sqlite3_commit_hook( 7 sqlite3 *db, /* Attach the hook to this database */ 8 int (*xCallback)(void*), /* Function to invoke on each commit */ 9 void *pArg /* Argument to the function */10 )
如果回调函数返回非零值,提交将装换为回滚。
对于xCallback,如果为NULL,将禁止当前注册函数;如果无注册过,sqlite3_commit_hook()将返回NULL;如果以前注册过,sqlite3_commit_hook()将返回以前的参数data值。
2、回滚钩子
回滚钩子关注给定连接上的回滚事件。
1 /*2 ** Register a callback to be invoked each time a transaction is rolled3 ** back by this database connection.4 */5 void *sqlite3_rollback_hook(6 sqlite3 *db, /* Attach the hook to this database */7 void (*xCallback)(void*), /* Callback function */8 void *pArg /* Argument to the function */9 )
不管是显示的回滚命令、隐式错误还是违反约束导致的回滚。由于数据库连接关闭导致的自动回滚,将如法触发回调函数。与sqlite3_commit_hook()一样,每次调用时,提供新的回调函数将替换以前注册的回调函数。
3、更新钩子
用于检视给定连接上对行的所有更新、插入和删除操作。
1 /*2 ** Register a callback to be invoked each time a row is updated,3 ** inserted or deleted using this database connection.4 */5 void *sqlite3_update_hook(6 sqlite3 *db, /* Attach the hook to this database */7 void (*xCallback)(void*,int,char const *,char const *,sqlite_int64),8 void *pArg /* Argument to the function */9 )
xCallback的函数原型如下:
1 void callback(void* data,2 int operation_code,3 char const *db_name,4 char const *table_name,5 sqlite_int64 rowid);
参数data是由注册函数的pArg参数提供的。
operation_code取值SQLITE_INSET、SQLITE_UPDATE和SQLITE_DELETE。
db_name,table_name对应数据库名称和操作发生的表名称。
rowid为受影响的行。
系统表不会调用回调函数。如果之前存在回调函数,则返回值指向之前注册的回调函数数据的指针。
4、授权函数
允许监控或控制查询语句的编译。
1 SQLITE_API int sqlite3_set_authorizer(2 sqlite3*,3 int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),4 void *pUserData5 );
回调函数的原型:
1 static int authCallback(2 void *pClientData, //用户数据3 int op, //事件代码4 const char *z1, //事件具体相关的参数5 const char *z2, //事件具体相关的参数6 const char *z3, //数据库名称7 const char *z4 //触发器或视图名称8 )
参数op、z1、z2取值如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 #define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */ 2 #define SQLITE_CREATE_TABLE 2 /* Table Name NULL */ 3 #define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */ 4 #define SQLITE_CREATE_TEMP_TABLE 4 /* Table Name NULL */ 5 #define SQLITE_CREATE_TEMP_TRIGGER 5 /* Trigger Name Table Name */ 6 #define SQLITE_CREATE_TEMP_VIEW 6 /* View Name NULL */ 7 #define SQLITE_CREATE_TRIGGER 7 /* Trigger Name Table Name */ 8 #define SQLITE_CREATE_VIEW 8 /* View Name NULL */ 9 #define SQLITE_DELETE 9 /* Table Name NULL */10 #define SQLITE_DROP_INDEX 10 /* Index Name Table Name */11 #define SQLITE_DROP_TABLE 11 /* Table Name NULL */12 #define SQLITE_DROP_TEMP_INDEX 12 /* Index Name Table Name */13 #define SQLITE_DROP_TEMP_TABLE 13 /* Table Name NULL */14 #define SQLITE_DROP_TEMP_TRIGGER 14 /* Trigger Name Table Name */15 #define SQLITE_DROP_TEMP_VIEW 15 /* View Name NULL */16 #define SQLITE_DROP_TRIGGER 16 /* Trigger Name Table Name */17 #define SQLITE_DROP_VIEW 17 /* View Name NULL */18 #define SQLITE_INSERT 18 /* Table Name NULL */19 #define SQLITE_PRAGMA 19 /* Pragma Name 1st arg or NULL */20 #define SQLITE_READ 20 /* Table Name Column Name */21 #define SQLITE_SELECT 21 /* NULL NULL */22 #define SQLITE_TRANSACTION 22 /* Operation NULL */23 #define SQLITE_UPDATE 23 /* Table Name Column Name */24 #define SQLITE_ATTACH 24 /* Filename NULL */25 #define SQLITE_DETACH 25 /* Database Name NULL */26 #define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */27 #define SQLITE_REINDEX 27 /* Index Name NULL */28 #define SQLITE_ANALYZE 28 /* Table Name NULL */29 #define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */30 #define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */31 #define SQLITE_FUNCTION 31 /* NULL Function Name */32 #define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */33 #define SQLITE_COPY 0 /* No longer used */34 #define SQLITE_RECURSIVE 33 /* NULL NULL */
z3是数据库、临时数据库等的名称。
z4是负责访问尝试的最内层的触发器或视图,如果为NULL,表示这种访问是这届来自顶级的SQL语句。
在实现authCallback()函数时,可通过判断事件代码op和z1、z2来控制对数据库的操作。
5、交互式程序相关API
SQLITE_API void sqlite3_interrupt(sqlite3*);
使给定连接上的数据库操作终止,并尽早返回。该程序在响应用户中断行为时调用,例如图形界面中的取消按钮或命令行中Ctrl+C调用此例程。
1 /* 2 ** This routine sets the progress callback for an Sqlite database to the 3 ** given callback function with the given argument. The progress callback will 4 ** be invoked every nOps opcodes. 5 */ 6 void sqlite3_progress_handler( 7 sqlite3 *db, 8 int nOps, 9 int (*xProgress)(void*), 10 void *pArg11 )
该函数安装一个在sqlite3_exec()、sqlite3_step()和sqlite3_get_table()的回调函数。该函数目的是让应用在长时间运行的查询过程中为用户提供反馈信息。
如果进度回调函数返回非零值,将立即终止查询,任何更改将被回滚。如果查询较大事务,那么事务不会回滚,继续保持活动状态。此时,调用sqlite3_exec()将返回SQLITE_ABORT。
四、线程
不要尝试在UNIX平台系统调用fork()时,将连接传递给子进程,否则将无法工作。
1、共享缓存模型
允许一个进程中的多个连接使用共同的页缓存。该功能用于单个线程能够代表其他线程有效管理多个数据库连接的嵌入式服务器。
共享缓存模式中,实际的数据库连接存在于服务器线程中。应用线程通过某种机制向服务线程发送sql语句,服务器线程返回结果。
此模式下,数据库连接使用不同的并发模型和隔离级别。写数据库时,将不会影响读数据库;此时,读操作有可能看不到数据库背后的变化。
1)、读未提交隔离级别
如果将编译选项read_uncommitted设置为为true,连接不会在读取的表上加读锁。此时,另一个写操作可在连接读取的时候更改表。这可能导致不一致的查询结果,也意味着读取未提交模式中的连接既不阻止其他连接,也不会被其他连接阻止。
2)、解锁通知
1 SQLITE_API int sqlite3_unlock_notify(2 sqlite3 *pBlocked, /* Waiting connection */3 void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */4 void *pNotifyArg /* Argument to pass to xNotify */5 );
代码因存在锁竞争失败而可能返回SQLITE_LOCKED,可调用sqlit3_unlock_notify()处理这种情况。
当sqlit3_unlock_notify()调用返回SQLITE_LOCKED时,说明存在死锁。需要进行回滚操作;当返回SQLITE_OK时,sqlite3_setp()等函数会阻塞,直到获取锁。
参考:
2、线程与内存管理
SQLite有几个与线程和内存管理相关的函数,他们可指定堆大小、弹性堆栈限制,以及手动启动内存清理。
1 SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);2 3 SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
1 SQLITE_API int sqlite3_release_memory(int);
新程序应该使用sqlite3_soft_heap_limit64()函数,此函数将线程的当前堆设置为N字节,如果超过了N字节,将会自动调用sqlite3_release_memory(),返回值是实际释放的字节数。
使用上述API,需要在编译SQLite是启用预处理器指令SQLITE_ENABLE_MEMORY_MANAGEMENT,以启用内存管理。