在线文档教程
Sqlite
C界面 | C Interface

Online Backup API

在线备份 API

在线备份 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()时,应该只有一次调用 sqlite3_backup_finish()。

sqlite3_backup_init()

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()

函数 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()无法获得所需的文件系统锁定,则调用 busy-handler函数(如果指定了)。如果 busy-handler在锁可用之前返回非零值,则 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_step()会获取目标文件的排它锁。直到调用 sqlite3_backup_finish()或备份操作完成并且 sqlite3_backup_step()返回 SQLITE_DONE,才会释放排它锁。每次调用 sqlite3_backup_step()都会在源数据库上获得一个持续 sqlite3_backup_step()调用持续时间的共享锁。由于源数据库在 sqlite3_backup_step()的调用之间没有锁定,源数据库可能会在备份过程的中途进行修改。如果源数据库被外部进程修改或通过除备份操作使用的数据库连接以外的数据库连接修改,则备份将在下次调用 sqlite3_backup_step()时自动重新启动。

sqlite3_backup_finish()

当 sqlite3_backup_step()返回 SQLITE_DONE 时,或者应用程序希望放弃备份操作时,应用程序应通过将 sqlite3_backup 传递给 sqlite3_backup_finish()来销毁 sqlite3_backup。sqlite3_backup_finish() 接口释放与 sqlite3_backup 对象关联的所有资源。如果 sqlite3_backup_step()尚未返回 SQLITE_DONE,则回滚目标数据库上的任何活动写入事务。sqlite3_backup 对象无效,可能在调用 sqlite3_backup_finish()后不能使用。

无论 sqlite3_backup_step()是否完成,如果没有发生 sqlite3_backup_step()错误,sqlite3_backup_finish 返回的值为 SQLITE_OK。如果在同一 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()的同时调用它们,则可能返回无效值。