SQLite学习手册(SQLite在线备份)_SQLite

一、常用备份:

    下面的方法是比较简单且常用的SQLite数据库备份方式,见如下步骤:
    1). 使用SQLite API或Shell工具在源数据库文件上加共享锁。
    2). 使用Shell工具(cp或copy)拷贝数据库文件到备份目录。
    3). 解除数据库文件上的共享锁。
    以上3个步骤可以应用于大多数场景,而且速度也比较快,然而却存在一定的刚性缺陷,如:
    1). 所有打算在源数据库上执行写操作的连接都不得不被挂起,直到整个拷贝过程结束并释放文件共享锁。
    2). 不能拷贝数据到in-memory数据库。
    3). 在拷贝过程中,一旦备份数据库所在的主机出现任何突发故障,备份数据库可能会被破坏。
    在SQLite中提供了一组用于在线数据库备份的APIs函数(C接口),可以很好的解决上述方法存在的不足。通过该组函数,可以将源数据库中的内容拷贝到另一个数据库,同时覆盖目标数据库中的数据。整个拷贝过程可以以增量的方式完成,在此情况下,源数据库也不需要在整个拷贝过程中都被加锁,而只是在真正读取数据时加共享锁。这样,其它的用户在访问源数据库时就不会被挂起。

二、在线备份APIs简介:

    SQLite提供了以下3个APIs函数用于完成此操作,这里仅仅给出它们的基本用法,至于使用细节可以参考SQLite官方网站"APIs Reference"(http://www.sqlite.org/c3ref/backup_finish.html)。
    1). 函数sqlite3_backup_init()用于创建sqlite3_backup对象,该对象将作为本次拷贝操作的句柄传给其余两个函数。
    2). 函数sqlite3_backup_step()用于数据拷贝,如果该函数的第二个参数为-1,那么整个拷贝过程都将在该函数的一次调用中完成。
    3). 函数sqlite3_backup_finish()用于释放sqlite3_backup_init()函数申请的资源,以避免资源泄露。
    在整个拷贝过程中如果出现任何错误,我们都可以通过调用目的数据库连接的sqlite3_errcode()函数来获取具体的错误码。此外,如果sqlite3_backup_step()调用失败,由于sqlite3_backup_finish()函数并不会修改当前连接的错误码,因此我们可以在调用sqlite3_backup_finish()之后再获取错误码,从而在代码中减少了一次错误处理。见如下代码示例(来自SQLite官网):

复制代码 代码如下:

/*
** This function is used to load the contents of a database file on disk
** into the "main" database of open database connection pInMemory, or
** to save the current contents of the database opened by pInMemory into
** a database file on disk. pInMemory is probably an in-memory database,
** but this function will also work fine if it is not.
**
** Parameter zFilename points to a nul-terminated string containing the
** name of the database file on disk to load from or save to. If parameter
** isSave is non-zero, then the contents of the file zFilename are
** overwritten with the contents of the database opened by pInMemory. If
** parameter isSave is zero, then the contents of the database opened by
** pInMemory are replaced by data loaded from the file zFilename.
**
** If the operation is successful, SQLITE_OK is returned. Otherwise, if
** an error occurs, an SQLite error code is returned.
*/
int loadOrSaveDb(sqlite3 *pInMemory, const char *zFilename, int isSave){
  int rc;                   /* Function return code */
  sqlite3 *pFile;           /* Database connection opened on zFilename */
  sqlite3_backup *pBackup;  /* Backup object used to copy data */
  sqlite3 *pTo;             /* Database to copy to (pFile or pInMemory) */
  sqlite3 *pFrom;           /* Database to copy from (pFile or pInMemory) */

  /* Open the database file identified by zFilename. Exit early if this fails
  ** for any reason. */
  rc = sqlite3_open(zFilename, &pFile);
  if( rc==SQLITE_OK ){

    /* If this is a 'load' operation (isSave==0), then data is copied
    ** from the database file just opened to database pInMemory.
    ** Otherwise, if this is a 'save' operation (isSave==1), then data
    ** is copied from pInMemory to pFile.  Set the variables pFrom and
    ** pTo accordingly. */
    pFrom = (isSave ? pInMemory : pFile);
    pTo   = (isSave ? pFile     : pInMemory);

    /* Set up the backup procedure to copy from the "main" database of
    ** connection pFile to the main database of connection pInMemory.
    ** If something goes wrong, pBackup will be set to NULL and an error
    ** code and  message left in connection pTo.
    **
    ** If the backup object is successfully created, call backup_step()
    ** to copy data from pFile to pInMemory. Then call backup_finish()
    ** to release resources associated with the pBackup object.  If an
    ** error occurred, then  an error code and message will be left in
    ** connection pTo. If no error occurred, then the error code belonging
    ** to pTo is set to SQLITE_OK.
*/
    pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main");
    if( pBackup ){
      (void)sqlite3_backup_step(pBackup, -1);
      (void)sqlite3_backup_finish(pBackup);
    }
    rc = sqlite3_errcode(pTo);
  }

  /* Close the database connection opened on database file zFilename
  ** and return the result of this function. */
  (void)sqlite3_close(pFile);
  return rc;
}

三、高级应用技巧:

    在上面的例子中,我们是通过sqlite3_backup_step()函数的一次调用完成了整个拷贝过程。该实现方式仍然存在之前说过的挂起其它写访问连接的问题,为了解决该问题,这里我们将继续介绍另外一种更高级的实现方式--分片拷贝,其实现步骤如下:
    1). 函数sqlite3_backup_init()用于创建sqlite3_backup对象,该对象将作为本次拷贝操作的句柄传给其余两个函数。
    2). 函数sqlite3_backup_step()被调用用于拷贝数据,和之前方法不同的是,该函数的第二个参数不再是-1,而是一个普通的正整数,表示每次调用将会拷贝的页面数量,如5。
    3). 如果在函数sqlite3_backup_step()调用结束后,仍然有更多的页面需要被拷贝,那么我们将主动休眠250ms,然后再重复步骤2).
    4). 函数sqlite3_backup_finish()用于释放sqlite3_backup_init()函数申请的资源,以避免资源泄露。
    在上述步骤3)中我们主动休眠250ms,此期间,该拷贝操作不会在源数据库上持有任何读锁,这样其它的数据库连接在进行写操作时亦将不会被挂起。然而在休眠期间,如果另外一个线程或进程对源数据库进行了写操作,SQLite将会检测到该事件的发生,从而在下一次调用sqlite3_backup_step()函数时重新开始整个拷贝过程。唯一的例外是,如果源数据库不是in-memory数据库,同时写操作是在与拷贝操作同一个进程内完成,并且在操作时使用的也是同一个数据库连接句柄,那么目的数据库中数据也将被此操作同时自动修改。在下一次调用sqlite3_backup_step()时,也将不会有任何影响发生。  
    事实上,在SQLite中仍然提供了另外两个辅助性函数backup_remaining()和backup_pagecount(),其中前者将返回在当前备份操作中还有多少页面需要被拷贝,而后者将返回本次操作总共需要拷贝的页面数量。显而易见的是,通过这两个函数的返回结果,我们可以实时显示本次备份操作的整体进度,计算公式如下:
    Completion = 100% * (pagecount() - remaining()) / pagecount()
    见以下代码示例(来自SQLite官网):

复制代码 代码如下:

/*
** Perform an online backup of database pDb to the database file named
** by zFilename. This function copies 5 database pages from pDb to
** zFilename, then unlocks pDb and sleeps for 250 ms, then repeats the
** process until the entire database is backed up.
**
** The third argument passed to this function must be a pointer to a progress
** function. After each set of 5 pages is backed up, the progress function
** is invoked with two integer parameters: the number of pages left to
** copy, and the total number of pages in the source file. This information
** may be used, for example, to update a GUI progress bar.
**
** While this function is running, another thread may use the database pDb, or
** another process may access the underlying database file via a separate
** connection.
**
** If the backup process is successfully completed, SQLITE_OK is returned.
** Otherwise, if an error occurs, an SQLite error code is returned.
*/
int backupDb(
  sqlite3 *pDb,               /* Database to back up */
  const char *zFilename,      /* Name of file to back up to */
  void(*xProgress)(int, int)  /* Progress function to invoke */    
){
  int rc;                     /* Function return code */
  sqlite3 *pFile;             /* Database connection opened on zFilename */
  sqlite3_backup *pBackup;    /* Backup handle used to copy data */

  /* Open the database file identified by zFilename. */
  rc = sqlite3_open(zFilename, &pFile);
  if( rc==SQLITE_OK ){

    /* Open the sqlite3_backup object used to accomplish the transfer */
    pBackup = sqlite3_backup_init(pFile, "main", pDb, "main");
    if( pBackup ){

      /* Each iteration of this loop copies 5 database pages from database
      ** pDb to the backup database. If the return value of backup_step()
      ** indicates that there are still further pages to copy, sleep for
      ** 250 ms before repeating. */
      do {
        rc = sqlite3_backup_step(pBackup, 5);
        xProgress(
            sqlite3_backup_remaining(pBackup),
            sqlite3_backup_pagecount(pBackup)
        );
        if( rc==SQLITE_OK || rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
          sqlite3_sleep(250);
        }
      } while( rc==SQLITE_OK || rc==SQLITE_BUSY || rc==SQLITE_LOCKED );

      /* Release resources allocated by backup_init(). */
      (void)sqlite3_backup_finish(pBackup);
    }
    rc = sqlite3_errcode(pFile);
  }

  /* Close the database connection opened on database file zFilename
  ** and return the result of this function. */
  (void)sqlite3_close(pFile);
  return rc;
}

时间: 2024-10-13 11:44:56

SQLite学习手册(SQLite在线备份)_SQLite的相关文章

SQLite教程(九):在线备份_SQLite

一.常用备份:     下面的方法是比较简单且常用的SQLite数据库备份方式,见如下步骤:     1). 使用SQLite API或Shell工具在源数据库文件上加共享锁.     2). 使用Shell工具(cp或copy)拷贝数据库文件到备份目录.     3). 解除数据库文件上的共享锁.     以上3个步骤可以应用于大多数场景,而且速度也比较快,然而却存在一定的刚性缺陷,如:     1). 所有打算在源数据库上执行写操作的连接都不得不被挂起,直到整个拷贝过程结束并释放文件共享锁.

Sqlite学习笔记(四)&&SQLite-WAL原理(转)

Sqlite学习笔记(三)&&WAL性能测试中列出了几种典型场景下WAL的性能数据,了解到WAL确实有性能优势,这篇文章将会详细分析WAL的原理,做到知其然,更要知其所以然. WAL是什么       WAL(Write ahead logging)是一种日志模式,它是一种思想,普遍应用于关系型数据库.每个事务执行变更时,修改数据页,同时会产生日志,这样在事务提交后,不需要将修改的脏页刷盘,只需要将事务产生的日志落盘即可返回.WAL保证日志一定先于对应的脏页落盘,就是所谓的WAL.SQLI

SQLite数据库安装及基本操作指南_SQLite

1. 介绍 SQLite 是一个开源的嵌入式关系数据库,实现自包容.零配置.支持事务的SQL数据库引擎. 其特点是高度便携.使用方便.结构紧凑.高效.可靠. 与其他数据库管理系统不同,SQLite 的安装和运行非常简单,在大多数情况下 - 只要确保SQLite的二进制文件存在即可开始创建.连接和使用数据库.如果您正在寻找一个嵌入式数据库项目或解决方案,SQLite是绝对值得考虑. 2. 安装 SQLite on Windows 1)进入 SQL 下载页面:http://www.sqlite.or

XML轻松学习手册(2)XML概念

xml|概念 第二章 XML概念 导言 经过第一章的快速入门学习,你已经知道了XML是一种能够让你自己创造标识的语言,它可以将数据与格式从网页中分开,它可以储存数据和共享数据的特性使得XML无所不能.如果你希望深入学习XML,系统掌握XML的来龙去脉,那么我们首先还是要回到XML概念的问题上来.XML(Extensible Markup Language),一种扩展性标识语言."扩展性""标识""语言".每一个词都明确的点明了XML的重要特点和功

Google Interview University - 坚持完成这套学习手册,你就可以去 Google 面试了

本文讲的是Google Interview University - 坚持完成这套学习手册,你就可以去 Google 面试了, 这是我为了从 web 开发者(自学.非计算机科学学位)蜕变至 Google 软件工程师所制定的计划,其内容历时数月. 这一长列表是从 Google 的指导笔记 中萃取出来并进行扩展.因此,有些事情你必须去了解一下.我在列表的底部添加了一些额外项,用于解决面试中可能会出现的问题.这些额外项大部分是来自于 Steve Yegge 的"得到在 Google 工作的机会&quo

《ZEMAX光学设计超级学习手册》一一1.2 用户界面

1.2 用户界面 ZEMAX光学设计超级学习手册 启动ZEMAX后将进入ZEMAX默认的工作界面.ZEMAX的基本界面比较简单,包括一系列菜单和工具按钮,以及一个透镜数据编辑界面,如图1-8所示. 1.2.1 窗口类型 ZEMAX软件有许多不同类型的窗口,每种窗口各有不同的用途,主要包括: (1)主窗口:此窗口包含一块很大的空面积,其上方有工作区.标题栏.菜单栏.工具栏等.菜单栏中的命令一般来说可作用于当前光学系统的整体. (2)编辑窗口:ZEMAX软件中有5个不同的编辑器,分别是镜头数据编辑器

《MATLAB/Simulink系统仿真超级学习手册》——第2章 MATLAB编程基础 2.1 MATLAB工作环境

第2章 MATLAB编程基础 本书使用的MATLAB版本为MATLAB R.本章将较全面地介绍MATLAB正常运行的基本流程以及编程基础与技巧,帮助读者在领略MATLAB非凡能力的同时比较轻松地跨过MATLAB门槛,为后面学习MATLAB工具箱Simulink打下坚实的基础. 2.1 MATLAB工作环境 MATLAB/Simulink系统仿真超级学习手册 MATLAB提供了全新的工作环境,了解并熟悉该环境是使用MATLAB的基础.下面将介绍MATLAB主界面(包括工具栏.命令窗口等).文本编辑

《MATLAB神经网络超级学习手册》——2.4 M文件

2.4 M文件 MATLAB神经网络超级学习手册 M文件有两种形式:脚本文件(Script File)和函数文件(Function File).脚本文件通常用于执行一系列简单的MATLAB命令,运行时只需输入文件名字,MATLAB就会自动按顺序执行文件中的命令. 函数文件和脚本文件不同,它可以接受参数,也可以返回参数,在一般情况下,用户不能靠单独输入其文件名来运行函数文件,而必须由其他语句来调用,MATLAB的大多数应用程序都以函数文件的形式给出. 2.4.1 M文件概述 MATLAB提供了极其

《ABAQUS 6.14超级学习手册》——1.5 ABAQUS帮助文档

1.5 ABAQUS帮助文档 ABAQUS为用户提供了便捷和详实的帮助文档,帮助各个层次的用户完成自己的分析.下面将对ABAQUS的帮助文档进行简单的讲解. 1.5.1 ABAQUS帮助文档的内容 ABAQUS具有一套内容完整和充实的文档.除非特殊说明,用户都可从SIMULIA网站获得.常用的文档如下. (1)<ABAQUS入门指南>(Getting Started with ABAQUS). 该手册是针对初学者的入门指南,指导用户如何使用ABAQUS/CAE生成模型,使用ABAQUS/CAE