描述
此函数设置一个回调函数,只要尝试打开另一个线程或进程已锁定的数据库表时,该函数将被调用。
C / C ++语法
int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); |
PB语法
FUNCTION sqlite3_busy_handler ( _ BYVAL hDbc AS DWORD, _ BYVAL pBusyCallback AS DWORD, _ BYVAL pUserData AS DWORD _ ) AS LONG |
参数
pDb
[in]数据库连接句柄。
pBusyCallback
[in]回调函数的地址。如果忙回调为NULL,则在遇到锁时立即返回SQLITE_BUSY或SQLITE_IOERR_BLOCKED。如果忙回调不为NULL,则可以使用两个参数调用回调。默认的busy回调为NULL。
pUserData
[in]一个可选值,被转发到每个回调调用的第一个参数。
返回值
SQLITE_OK成功,失败时出现非零错误代码。
备注
当SQLite处于大型事务中时,SQLITE_BUSY错误将转换为SQLITE_IOERR_BLOCKED,其中所有更改都不适用于内存中缓存。SQLite已经在数据库文件上保留了一个RESERVED锁,但是它需要将此锁定升级到EXCLUSIVE,以便将缓存页面溢出到数据库文件中,而不会对并发读者造成危害。如果无法提升锁定,则内存中的缓存将处于不一致的状态,因此错误代码从相对良性的SQLITE_BUSY升级到更严重的SQLITE_IOERR_BLOCKED。此错误代码升级强制自动回滚更改。有关为什么这很重要的讨论,请参阅CorruptionFollowingBusyError维基页面。
忙碌处理程序的存在并不能保证在存在锁争用时将被调用。如果SQLite确定调用忙处理程序可能会导致死锁,则它将继续执行,并返回SQLITE_BUSY或SQLITE_IOERR_BLOCKED,而不是调用忙处理程序。考虑一个进程持有正在尝试提升到保留锁的读取锁的情况,而第二个进程持有正在尝试提升为独占锁的保留锁。第一个进程无法继续进行,因为它被第二个进程阻止,第二个进程无法继续进行,因为它被第一个进程阻止。如果这两个进程调用忙碌的处理程序,也不会有任何进展。因此,SQLite为第一个进程返回SQLITE_BUSY,希望这将引发第一个进程释放其读取锁并允许第二个进程继续。
只能为每个数据库连接定义一个忙碌的处理程序。设置新的忙碌处理程序将清除任何先前设置的处理程序。请注意,呼叫sqlite3_busy_timeout也将设置或清除忙碌处理程序。
忙碌的回调不应该采取任何修改调用繁忙处理程序的数据库连接的操作。任何此类操作都会导致未定义的行为。
忙碌处理程序不能关闭调用忙碌处理程序的数据库连接或准备好的语句。
C ++实现代码
/*
** This function sets the busy callback for an Sqlite database to the
** given callback function with the given argument.
*/
SQLITE_API int sqlite3_busy_handler(
sqlite3 *db,
int (*xBusy)(void*,int),
void *pArg
){
sqlite3_mutex_enter(db->mutex);
db->busyHandler.xFunc = xBusy;
db->busyHandler.pArg = pArg;
db->busyHandler.nBusy = 0;
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}