注册回调函数处理SQLITE_BUSY错误

来源:互联网 发布:阿里云 广告 编辑:程序博客网 时间:2024/06/05 02:26

原文标题:Register A Callback To Handle SQLITE_BUSY Errors


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


  这个函数设置了一个回调函数,当试图打开一个在另一个线程或进程中被锁住的表时,该回调函数可能会被调用。 (译注:这里用的是"可能"被调用,后面会有解译)

 

  当遇到数据库被锁时,如果回调函数是NULL,那么SQLITE_BUSY或者SQLITE_IOERR_BLOCKED会立刻返回;如果回调函数不为空时,回调函数可能会被调用并传递给它两个参数。

  第一个参数是当你调用sqlite_busy_handle函数时传递给它的一个void*的参数的拷贝;第二个参数是因此这次锁事件,该回调函数被调用的次数。

  如果回调函数返回0时,将不再尝试再次访问数据库而返回SQLITE_BUSY或者SQLITE_IOERR_BLOCKED。

  如果回调函数返回非0, 将会不断尝试操作数据库。

  

  当发生锁争夺时,回调函数不保证每次一定会被调用。当SQLITE检测到调用回调函数会引发死锁现象时,将会直接返回SQLITE_BUSY或者SQLITE_IOERR_BLOCKED而不是调用回调函数。试想下面的情况,操作A拥有一个可读锁并尝试提升为保留锁,而操作B拥有一个保留锁并尝试提升为独占锁,A无法继续操作,因为B的保留锁阻止创建新的保留锁;而B也无法继续操作因为A的可读锁未释放,保留锁就无法提升为独占锁。如果这时两个操作都调用回调函数,那么将都无法继续处理。因此,在这样的情况下,操作A将会返回SQLITE_BUSY,以释放它拥有的可读锁,从而使得操作B可以继续进行。

 

  默认的回调函数为空。

 

  当sqlite处于一个大的事务中,以至于内存缓冲区无法保留所有修改,此时发生的SQLITE_BUSY错误将被转换成SQLITE_IOERR_BLOCKED错误。sqlite此时已经拥有保留锁,并尝试提升为独占锁后将缓冲页面刷新到数据库文件中从而不影响其它并发的读取操作,如果获取独占锁失败,那么内存缓冲区中的数据将处于一个不一致的状态,此时错误代码从相对良好的SQLITE_BUSY提升到为严重的SQLITE_IOERR_BLOCKED。错误的提升会造成强制的回滚。可从CorruptionFollowingBusyError维基页面上查看这样处理的重要性的相关讨论。(译注:对于缓冲区不够的大的事务,sqlite会将部分修改写入回滚日志中,可参阅数据库文件完整性相关的文章)

  一个数据库连接只能有一个回调函数,设置新的回调函数将会覆盖原来的。需要注意,调用sqlite3_busy_timeout()也可能会设置或清除当前的回调函数。

  回调函数中不要对数据库连接做任何操作,所做的任何操作,可能带来未定义的结果。

  回调函数中一定不要关闭数据库连接,或者关闭引发回调函数的语句对象。

原创粉丝点击