SQLite C 接口
在线备份 API。
sqlite3_backup *sqlite3_backup_init( sqlite3 *pDest, /* Destination database handle */ const char *zDestName, /* Destination database name */ sqlite3 *pSource, /* Source database handle */ const char *zSourceName /* Source database name */ ); int sqlite3_backup_step(sqlite3_backup *p, int nPage); int sqlite3_backup_finish(sqlite3_backup *p); int sqlite3_backup_remaining(sqlite3_backup *p); int sqlite3_backup_pagecount(sqlite3_backup *p);
备份 API 将一个数据库的内容复制到另一个数据库。它对于创建数据库备份或将内存数据库复制到持久文件或从持久文件中复制很有用。
另请参阅:使用 SQLite 在线备份 API
在备份操作期间,SQLite 在目标数据库文件上持有一个打开的写事务。源数据库仅在读取时才被读取锁定;它不会在整个备份操作中持续锁定。因此,可以在实时源数据库上执行备份,而不会在备份进行时阻止其他数据库连接读取或写入源数据库。
要执行备份操作:
- sqlite3_backup_init()被调用一次来初始化备份,
- sqlite3_backup_step()被调用一次或多次以在两个数据库之间传输数据,最后
- 调用sqlite3_backup_finish()以释放与备份操作相关的所有资源。
sqlite3_backup_init(D,N,S,M) 的 D 和 N 参数分别是与目标数据库关联的 数据库连接和数据库名称。主数据库的数据库名称是“main”,临时数据库的数据库名称是“temp”,或者附加数据库的ATTACH语句中 AS 关键字后指定的名称。传递给 sqlite3_backup_init(D,N,S,M) 的 S 和 M 参数分别标识源数据库的数据库连接 和数据库名称。源和目标数据库连接(参数 S 和 D)必须不同,否则 sqlite3_backup_init(D,N,S,M) 将失败并出现错误。
如果目标数据库上已经打开了读或读写事务,则调用 sqlite3_backup_init() 将失败,返回 NULL。
如果sqlite3_backup_init(D,N,S,M)发生错误,则返回NULL,并在目标数据库连接D中保存错误码和错误信息。调用sqlite3_backup_init()失败的错误码和信息可以使用sqlite3_errcode()、sqlite3_errmsg()和/或 sqlite3_errmsg16()函数检索。成功调用 sqlite3_backup_init() 会返回一个指向 sqlite3_backup对象的指针。sqlite3_backup对象可以与 sqlite3_backup_step() 和 sqlite3_backup_finish() 函数一起使用来执行指定的备份操作。
函数 sqlite3_backup_step(B,N) 将在sqlite3_backup对象 B指定的源数据库和目标数据库之间复制最多 N 个页面。如果 N 为负数,则复制所有剩余的源页面。如果 sqlite3_backup_step(B,N) 成功复制 N 页并且还有更多页需要复制,则函数返回SQLITE_OK。如果 sqlite3_backup_step(B,N) 成功完成将所有页面从源复制到目标,则它返回SQLITE_DONE。如果在运行 sqlite3_backup_step(B,N) 时发生错误,则返回错误代码。除了SQLITE_OK和 SQLITE_DONE,对 sqlite3_backup_step() 的调用可能会返回SQLITE_READONLY, SQLITE_NOMEM、SQLITE_BUSY、SQLITE_LOCKED或 SQLITE_IOERR_XXX扩展错误代码。
sqlite3_backup_step() 可能返回SQLITE_READONLY如果
- 目标数据库以只读方式打开,或者
- 目标数据库正在使用预写日志日志记录并且目标和源页面大小不同,或者
- 目标数据库是内存数据库,目标和源页面大小不同。
如果 sqlite3_backup_step() 无法获得所需的文件系统锁,则调用忙处理函数 (如果已指定)。如果忙处理程序在锁定可用之前返回非零值,则 SQLITE_BUSY返回给调用者。在这种情况下,可以稍后重试对 sqlite3_backup_step() 的调用。如果在调用 sqlite3_backup_step() 时正在使用源 数据库连接 写入源数据库,则立即返回SQLITE_LOCKED。同样,在这种情况下,可以稍后重试对 sqlite3_backup_step() 的调用。如果 SQLITE_IOERR_XXX、SQLITE_NOMEM或 SQLITE_READONLY被返回,那么重试对 sqlite3_backup_step() 的调用就没有意义了。这些错误被认为是致命的。应用程序必须接受备份操作失败并将备份操作句柄传递给 sqlite3_backup_finish() 以释放相关资源。
对 sqlite3_backup_step() 的第一次调用获得了对目标文件的独占锁。在调用 sqlite3_backup_finish() 或备份操作完成并且 sqlite3_backup_step() 返回SQLITE_DONE之前,独占锁不会被释放。每次调用 sqlite3_backup_step() 都会获得一个共享锁在 sqlite3_backup_step() 调用期间持续的源数据库上。因为源数据库在调用 sqlite3_backup_step() 之间没有被锁定,所以源数据库可能会在备份过程中途被修改。如果源数据库被外部进程或通过备份操作使用的数据库连接之外的数据库连接修改,则备份将在下一次调用 sqlite3_backup_step() 时自动重新启动。如果使用与备份操作相同的数据库连接修改源数据库,则备份数据库会同时自动更新。
当 sqlite3_backup_step() 返回SQLITE_DONE时,或者当应用程序希望放弃备份操作时,应用程序应该通过将sqlite3_backup传递给 sqlite3_backup_finish() 来销毁它。sqlite3_backup_finish() 接口释放与sqlite3_backup对象关联的所有资源。如果 sqlite3_backup_step() 尚未返回SQLITE_DONE,则回滚目标数据库上的任何活动写事务。sqlite3_backup对象无效,不能在调用 sqlite3_backup_finish() 后使用。
如果没有发生 sqlite3_backup_step() 错误,则 sqlite3_backup_finish返回的值为SQLITE_OK,无论 sqlite3_backup_step() 是否完成。如果在同一sqlite3_backup对象上的任何先前 sqlite3_backup_step() 调用期间发生内存不足情况或 IO 错误,则 sqlite3_backup_finish() 返回相应的错误代码。
从 sqlite3_backup_step()返回SQLITE_BUSY或SQLITE_LOCKED不是永久性错误,不会影响 sqlite3_backup_finish() 的返回值。
sqlite3_backup_remaining() 和 sqlite3_backup_pagecount()
sqlite3_backup_remaining() 例程返回在最近的 sqlite3_backup_step() 结束时仍要备份的页数。sqlite3_backup_pagecount() 例程在最近的 sqlite3_backup_step() 结束时返回源数据库中的总页数。这些函数返回的值仅由 sqlite3_backup_step() 更新。如果以更改源数据库大小或剩余页数的方式修改源数据库,则这些更改不会反映在 sqlite3_backup_pagecount() 和 sqlite3_backup_remaining() 的输出中,直到下一个 sqlite3_backup_step() 之后。
并发使用数据库句柄
当备份操作正在进行或正在初始化时,应用程序可能会将源数据库连接用于其他目的。如果 SQLite 被编译并配置为支持线程安全数据库连接,那么源数据库连接可以在其他线程中同时使用。
但是,应用程序必须保证在 调用 sqlite3_backup_init() 之后和相应调用 sqlite3_backup_finish() 之前,目标数据库连接不会(通过任何线程)传递给任何其他 API。SQLite 目前不会检查应用程序是否错误地访问了目标数据库连接 ,因此不会报告任何错误代码,但操作可能会出现故障。在备份过程中使用目标数据库连接也可能导致互斥死锁。
如果以共享缓存模式运行,应用程序必须保证在备份运行时不访问目标数据库使用的共享缓存。实际上,这意味着应用程序必须保证正在备份的磁盘文件不会被进程内的任何连接访问,而不仅仅是传递给 sqlite3_backup_init() 的特定连接。
sqlite3_backup对象本身是部分线程安全的。多个线程可以安全地对 sqlite3_backup_step() 进行多个并发调用。但是,严格来说,sqlite3_backup_remaining() 和 sqlite3_backup_pagecount() API 并不是线程安全的。如果在另一个线程调用 sqlite3_backup_step() 的同时调用它们,则它们可能返回无效值。