Small. Fast. Reliable.
Choose any three.

SQLite C接口

解锁通知

int sqlite3_unlock_notify(
  sqlite3 * pBlocked,/ *等待连接* /
  void(* xNotify)(void ** apArg,int nArg),/ *用于调用* /的回调函数
  * pNotifyArg / *传递给xNotify的参数* /
);

在共享缓存模式下运行时,如果无法获得共享缓存上所需的锁或共享缓存内的各个表,则数据库操作可能会失败并显示SQLITE_LOCKED错误。有关共享缓存锁定的说明,请参见 SQLite共享缓存模式。该API可用于注册当前持有所需锁的连接放弃SQLite时SQLite将调用的回调。仅当库是使用已定义的SQLITE_ENABLE_UNLOCK_NOTIFY C预处理器符号编译的时,此API才可用 。

另请参见:使用SQLite解锁通知功能

当数据库连接通过提交或回滚完成当前事务时,将释放共享缓存锁。

当连接(称为阻止的连接)无法获取共享缓存锁并且SQLITE_LOCKED返回给调用方时,已锁定所需资源的数据库连接(阻止的连接)的标识存储在内部。应用程序收到SQLITE_LOCKED错误后,它可以使用被阻止的连接句柄作为第一个参数来调用sqlite3_unlock_notify()方法,以注册将在结束当前连接的事务结束时调用的回调。从 结束阻塞连接的事务的sqlite3_stepsqlite3_close调用中调用该回调。

如果在多线程应用程序中调用sqlite3_unlock_notify(),则在调用sqlite3_unlock_notify()时,阻塞连接可能已经完成了其事务。如果发生这种情况,则会在对sqlite3_unlock_notify()的调用内立即调用指定的回调。

如果被阻止的连接正试图在共享缓存表上获取写锁定,并且当前有多个连接在同一表上拥有读锁定,则SQLite会任意选择其他连接之一作为阻止联系。

被阻止的连接最多可以注册一个解锁通知回调。如果在被阻止的连接已具有已注册的解锁通知回调的情况下调用sqlite3_unlock_notify(),则新的回调将替换旧的回调。如果使用空指针作为第二个参数调用sqlite3_unlock_notify(),则将取消所有现有的unlock-notify回调。也可以通过使用sqlite3_close()关闭被阻止的连接来取消被阻止的连接的解锁通知回调。

解锁通知通知回调不是可重入的。如果应用程序从解锁通知回调中调用任何sqlite3_xxx API函数,则可能导致崩溃或死锁。

除非检测到死锁(请参见下文),否则sqlite3_unlock_notify()始终返回SQLITE_OK。

回调调用详细信息

注册了解锁通知回调后,应用程序将提供一个void *指针,该指针在调用时将传递给回调。但是,回调函数的签名允许SQLite向其传递一个void *上下文指针数组。传递给unlock-notify回调的第一个参数是一个指向void *指针数组的指针,第二个参数是该数组中条目的数量。

当阻塞连接的事务结束时,可能有多个阻塞连接已注册用于解锁通知回调。如果两个或多个这样的阻塞连接指定了相同的回调函数,则无需多次调用该回调函数,而是将阻塞连接指定的void *上下文指针集捆绑到一个数组中,以调用一次。这使应用程序有机会确定与未阻塞数据库连接集有关的所有操作的优先级。

死锁检测

假设在注册了一个解锁通知回调之后,数据库在采取任何进一步的操作(合理的假设)之前等待该回调被发出,那么使用此API可能会导致应用程序死锁。例如,如果连接X等待连接Y的事务结束,并且类似地连接Y等待连接X的事务,则两个连接都不会继续进行,并且系统可能会无限期保持死锁。

为了避免这种情况,sqlite3_unlock_notify()执行死锁检测。如果对sqlite3_unlock_notify()的给定调用将使系统处于死锁状态,则将返回SQLITE_LOCKED,并且不会注册任何解锁通知回调。如果连接A已在连接B的事务结束时注册了解锁通知回调,并且连接B本身已在连接A的事务结束时注册了解锁通知回调,则该系统处于死锁状态。还检测到间接死锁,因此,如果连接B已在连接C的事务结束时注册了用于解锁通知回调的连接,则该系统也被认为是死锁,其中连接C正在等待连接A。允许的。

“ DROP TABLE”异常

当调用sqlite3_step()返回SQLITE_LOCKED时,几乎总是适合调用sqlite3_unlock_notify()。但是,有一个例外。当执行“ DROP TABLE”或“ DROP INDEX”语句时,SQLite检查当前是否有任何执行的SELECT语句属于同一连接。如果存在,则返回SQLITE_LOCKED。在这种情况下,没有“阻塞连接”,因此调用sqlite3_unlock_notify()会导致立即调用unlock-notify回调。如果应用程序随后再次尝试“ DROP TABLE”或“ DROP INDEX”查询,则可能会导致无限循环。

解决此问题的一种方法是检查sqlite3_step()调用返回的扩展错误代码。如果存在阻塞连接,则扩展错误代码将设置为SQLITE_LOCKED_SHAREDCACHE。否则,在特殊的“ DROP TABLE / INDEX”情况下,扩展的错误代码仅为SQLITE_LOCKED。

另请参见 对象常量函数的列表