小巧、快速、可靠。
三选其二。

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 在整个备份操作期间对目标数据库文件保持写事务打开。源数据库仅在读取时被读锁;它不会在整个备份操作期间持续锁定。因此,可以在活动源数据库上执行备份,而不会阻止其他数据库连接在备份进行时读取或写入源数据库。

要执行备份操作

  1. sqlite3_backup_init() 被调用一次来初始化备份,
  2. sqlite3_backup_step() 被调用一次或多次来传输两个数据库之间的数据,最后
  3. 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_errcode()sqlite3_errmsg() 和/或 sqlite3_errmsg16() 函数检索失败调用 sqlite3_backup_init() 的错误代码和消息。成功调用 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_OKSQLITE_DONE 之外,调用 sqlite3_backup_step() 可能会返回 SQLITE_READONLYSQLITE_NOMEMSQLITE_BUSYSQLITE_LOCKEDSQLITE_IOERR_XXX 扩展错误代码。

sqlite3_backup_step() 可能会返回 SQLITE_READONLY,如果

  1. 目标数据库以只读方式打开,或者
  2. 目标数据库使用预写日志记录,并且目标页面大小与源页面大小不同,或者
  3. 目标数据库是内存数据库,并且目标页面大小与源页面大小不同。

如果 sqlite3_backup_step() 无法获取所需的 文件系统 锁,则会调用 繁忙处理程序函数(如果指定了)。如果繁忙处理程序在锁可用之前返回非零值,则 SQLITE_BUSY 会返回给调用者。在这种情况下,可以稍后重试调用 sqlite3_backup_step()。如果在调用 sqlite3_backup_step() 时,源 数据库连接 用于写入源数据库,则会立即返回 SQLITE_LOCKED。同样,在这种情况下,可以稍后重试调用 sqlite3_backup_step()。如果返回 SQLITE_IOERR_XXXSQLITE_NOMEMSQLITE_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_finish()

当 sqlite3_backup_step() 返回 SQLITE_DONE 或当应用程序希望放弃备份操作时,应用程序应该通过将它传递给 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_finish() 返回的值为 SQLITE_OK,无论 sqlite3_backup_step() 是否完成。如果在同一 sqlite3_backup 对象上的任何先前 sqlite3_backup_step() 调用期间发生内存不足情况或 IO 错误,则 sqlite3_backup_finish() 将返回相应的 错误代码

从 sqlite3_backup_step() 返回的 SQLITE_BUSYSQLITE_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_step() 之后,这些更改才会反映在 sqlite3_backup_pagecount() 和 sqlite3_backup_remaining() 的输出中。

数据库句柄的并发使用

应用程序可以在备份操作正在进行或正在初始化时,出于其他目的使用源 数据库连接。如果 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() 的同时被调用,则它们可能会返回无效值。

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