对于很多嵌入式数据库来说都有对于的内存数据库模式,SQLite也不例外。内存数据库常常用于极速、实时的场景,一个很好的应用的场景是富客户端的缓存数据,一般富客户端的缓存常常需要分为落地和非落地两种,而反应到SQLite上就是主要两种模式,一种是文件类型的数据库,一种是内存模式的。而我们常常需要做的是系统启动初从文件数据库加载到内存数据库,然后在系统退出或定时的将内存数据回写到文件数据库。这种导入和导出操作,在C#版本的SQLite库中已经原生进行了支持。而C版本中实际上对应了三个函数,你可以参照SQLite Online Backup API 。

其实本人在查找SQLite的内存模式和文件模式相互备份资料的时候,发现关于使用System.Data.SQLite.dll来进行两种模式相互备份的例子比较少,而且在国内的许多网站上找不到可以直接复用的代码,即时找到了也总是夹杂着很多C版本的实现,总是让人有些摸不着头脑。虽然如此,功夫不负有心人,在stackoverflow上找到了自己想要的代码,通过反编译看System.Data.SQLite.dll看SQLiteConnection中有一个方法BackupDatabase(......),通过它可以实现数据库间的备份。

BackupDatabase(......)方法的反编译的源码如下:

// The method in System.Data.SQLite.SQLiteConnection
        public void BackupDatabase(SQLiteConnection destination, string destinationName, string sourceName, int pages, SQLiteBackupCallback callback, int retryMilliseconds)
        {
            //省略参数检查和连接状态检查代码
            //
            SQLiteBase sql = this._sql;
            if (sql == null)
            {
                throw new InvalidOperationException("Connection object has an invalid handle.");
            }
            SQLiteBackup sQLiteBackup = null;
            try
            {
                sQLiteBackup = sql.InitializeBackup(destination, destinationName, sourceName);
                bool flag;
                while (sql.StepBackup(sQLiteBackup, pages, out flag) && (callback == null || callback(this, sourceName, destination, destinationName, pages, sql.RemainingBackup(sQLiteBackup), sql.PageCountBackup(sQLiteBackup), flag)))
                {
                    if (flag && retryMilliseconds >= 0)
                    {
                        Thread.Sleep(retryMilliseconds);
                    }
                    if (pages == 0)
                    {
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                if ((this._flags & SQLiteConnectionFlags.LogBackup) == SQLiteConnectionFlags.LogBackup)
                {
                    SQLiteLog.LogMessage(0, string.Format(CultureInfo.CurrentCulture, "Caught exception while backing up database: {0}", new object[]
			{
				ex
			}));
                }
                throw;
            }
            finally
            {
                if (sQLiteBackup != null)
                {
                    sql.FinishBackup(sQLiteBackup);
                }
            }
        }

从上面这段代码我们可以简单的看出,实际上备份还是通过InitializeBackup,StepBackup,FinishBackup这三个方法来实现。这三个方法分别对应的本地方法是sqlite3_backup_init,sqlite3_backup_step,sqlite3_backup_finish;关于这个三个方法的说明可以参考SQLite Online Backup API 。

接下来,将直接贴代码来展示如何在C#中使用System.Data.SQLite.dll来进行SQLite文件数据库与内存数据库相互备份。

//
//  软件版权: http://xiexiuli.cnblogs.com/
//  作者:     xiexiuli
//  创建时间: 2014-01-20
//  功能说明: SQLite内存数据库模式的管理器
//  修改历史:
//
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.IO;

namespace LongThinking.Data
{
    /// <summary>
    /// SQLite内存数据库模式的处理器
    /// </summary>
    public class SQLiteMemoryManager : IDisposable
    {
        /// <summary>
        /// 每个内存数据库都保持一个自己的连接
        /// </summary>
        private SQLiteConnection _globalConnection;

        #region 构造函数
        public SQLiteMemoryManager()
        {
            var str = "Data Source=:memory:;Version=3;New=True;";
            _globalConnection = new SQLiteConnection(str);
            _globalConnection.Open();
        }
        #endregion 

        #region 备份数据库
        /// <summary>
        /// 备份数据库
        /// </summary>
        /// <param name="dbFileConnectString">指定到文件数据库路径的连接串</param>
        /// <param name="isFileToMemory">
        /// 是否是文件数据库备份到内存数据库;
        /// isFileToMemory为true指的是从文件数据库导入到当前内存数据库;
        /// isFileToMemory为false指的是从当前内存数据库导出到文件数据库。
        /// </param>
        public void BackupDatabase(string dbFileConnectionString, bool isFileToMemory)
        {
            using (SQLiteConnection dbfileConnection = new SQLiteConnection(dbFileConnectionString))
            {
                this.BackupDatabase(dbfileConnection, isFileToMemory);
            }
        }

        /// <summary>
        /// 备份数据库
        /// </summary>
        /// <param name="dbPath">指定到文件数据库的文件全路径</param>
        /// <param name="password">文件数据库密码</param>
        /// <param name="isFileToMemory">
        /// 是否是文件数据库备份到内存数据库;
        /// isFileToMemory为true指的是从文件数据库导入到当前内存数据库;
        /// isFileToMemory为false指的是从当前内存数据库导出到文件数据库。
        /// </param>
        public void BackupDatabase(string dbPath, string password, bool isFileToMemory)
        {
            string dbFileConnectString = "Data Source=" + dbPath + ";Pooling=true;FailIfMissing=false;Password=" + password;
            using (SQLiteConnection dbfileConnection = new SQLiteConnection(dbFileConnectString))
            {
                this.BackupDatabase(dbfileConnection, isFileToMemory);
            }
        }

        /// <summary>
        /// 备份数据库
        /// </summary>
        /// <param name="dbfileConnection">文件数据库的连接,该连接状态需要是打开的或者是未打开过;关闭状态的连接,默认会帮你打开</param>
        /// <param name="isFileToMemory">
        /// 是否是文件数据库备份到内存数据库;
        /// isFileToMemory为true指的是从文件数据库导入到当前内存数据库;
        /// isFileToMemory为false指的是从当前内存数据库导出到文件数据库。
        /// </param>
        public void BackupDatabase(SQLiteConnection dbfileConnection, bool isFileToMemory)
        {
            //如果连接是关闭状态就打开
            if (dbfileConnection.State == ConnectionState.Closed)
            {
                dbfileConnection.Open();
            }

            if (isFileToMemory)
            {
                dbfileConnection.BackupDatabase(_globalConnection, "main", "main", -1, null, 0);
            }
            else
            {
                _globalConnection.BackupDatabase(dbfileConnection, "main", "main", -1, null, 0);
            }
        }

        #endregion

        #region 销毁
        ~SQLiteMemoryManager()
        {
            this.Dispose(true);
        }

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_globalConnection != null)
                {
                    _globalConnection.Dispose();
                }
            }
        }
        #endregion
    }
}

  上面的代码我已经删除很多数据操作的方法,等我测试完那些操作方法将提供完整版的类和工程供大家下载。

参考:

http://www.sqlite.org/backup.html

http://stackoverflow.com/questions/17298988/system-data-sqlite-backupdatabase-throws-not-an-error

【原创】System.Data.SQLite内存数据库模式的更多相关文章

  1. 启用SQLite的Data Provider 运行WECOMPANYSITE时遇到ERROR CREATING CONTEXT 'SPRING.ROOT': ERROR THROWN BY A DEPENDENCY OF OBJECT 'SYSTEM.DATA.SQLITE'

    从网上下载的源码WeCompanySite,运行时报错 Error creating context 'spring.root': Error thrown by a dependency of ob ...

  2. .Net4.0以上使用System.Data.Sqlite

    最近对Sqlite感兴趣,就尝试了一下用c#连接,我用的版本是vs2013,默认开发环境是.net4.5,,按照网上的教材,下载了System.Data.Sqlite,然后写了下面这个简单的测试代码, ...

  3. IIS发布网站出现“未能加载文件或程序集“System.Data.SQLite”或它的某一个依赖项。”的解决方法

    未能加载文件或程序集“System.Data.SQLite”或它的某一个依赖项.试图加载格式不正确的程序.              说明: 执行当前 Web 请求期间,出现未经处理的异常.请检查堆栈 ...

  4. 引用64位dll时候出现 未能加载文件或程序集“System.Data.SQLite”或它的某一个依赖项。试图加载格式不正确的程序。

    引用64位dll时候出现 未能加载文件或程序集“System.Data.SQLite”或它的某一个依赖项.试图加载格式不正确的程序. 需要在web.config增加配置 <startup use ...

  5. Could not load file or assembly 'System.Data.SQLite' or one of its dependencies

    试图加载格式不正确的程 异常类型 异常消息Could not load file or assembly 'System.Data.SQLite' or one of its dependencies ...

  6. System.Data.SQLite

    SQLite介绍 在介绍System.Data.SQLite之前需要介绍一下SQLite,SQLite是一个类似于Access的单机版数据库管理系统,它将所有数据库的定义(包括定义.表.索引和数据本身 ...

  7. 未能加载文件或程序集“System.Data.SQLite.DLL”或它的某一个依赖项

    今天在部署code到测试环境的时候 出现了未能加载文件或程序集"System.Data.SQLite.DLL"或它的某一个依赖项 这个错误,其实错误的的原因有很多,1.典型的是是版 ...

  8. SQLite 解决:Could not load file or assembly 'System.Data.SQLite ... 试图加载格式不正确的程序/or one of its dependencies. 找不到指定的模块。

     Could not load file or assembly 'System.Data.SQLite.dll' or one of its dependencies. 找不到指定的模块. 错误提示 ...

  9. 能加载文件或程序集“System.Data.SQLite”或它的某一个依赖项。试图加载格式不正确的程序。

    现象: 能加载文件或程序集“System.Data.SQLite”或它的某一个依赖项.试图加载格式不正确的程序.

随机推荐

  1. 几个Linux常见命令

    ls 作用:查看目录下的文件 格式:直接ls查看当前所在目录,或者  ls 参数 /目录名 参数: -l 查看详细信息 -a 显示隐藏文件 .   表示当前目录 ..  上级目录 -G 用不同颜色标记 ...

  2. [转]CSS vertical-align属性详解 作者:黄映焜

      CSS vertical-align属性详解 posted @ 2014-08-26 17:44 黄映焜   前言:关于vertical-align属性. 实践出真知. 垂直居中. 第二种用法. ...

  3. CSS3旋转图片效果收集

    火狐中文网图片效果: [http://i.firefoxchina.cn/?www.firefoxchina.cn] .news-img-wrapper:hover img {     transfo ...

  4. Android——ExpandableListView事件拦截

    1.满足条件 如果使用ExpandableListView,需要子item响应一个事件,比如重新启动一个新的activity,需要满足下面的条件: (1).修改Adapter返回值 覆写BaseExp ...

  5. 常用的方法,读取XML节点并赋值给List集合

    一.前言 很多时候也可以直接在XML文件中配置好节点,在程序需要用到的时候,修改XML文件并不需要重新编译,这里是在极光推送中拿出来的一部分代码.代码简单,大家直接看例子吧. 二.实现过程 1.新创建 ...

  6. 域名变更后获取cookie

    有个朋友问我,域名更换后怎么获取原有域名下的cookie,当时第一反应是域名都不存在还怎么获取cookie. 后面想想似乎是可以的,使用新域名后可以保留原有域名,通过jsonp或iframe跨域获取原 ...

  7. 第二章——第二节 IPC机制的概述和使用

    一.Serialiable与Paracle ①.作用    ②.使用 二.Binder与AIDL ①.各自的作用 三.如何使用IPC机制 举例 四.IPC机制的原理 ①.流程图  ②.自己编译自动生成 ...

  8. python笔记之调用系统命令

    python笔记之调用系统命令 目前我使用到的python中执行cmd的方式有三种 使用os.system("cmd") 该方法在调用完shell脚本后,返回一个16位的二进制数, ...

  9. postgresql数据库导入导出

    在shell中用命令pg_dump将数据库data1导出到一个文件中 pg_dump -d data1 -f test.txt 或者 pg_dump -d data1 > test.sql 然后 ...

  10. Azure上A/D系列虚拟机到DS系列迁移(2)

    11. 该脚本会检测环境,停止虚拟机,拷贝VHD文件,创建磁盘等等,知道出现如下类似画面,他会暂停等待用户操作: 后面这几个步骤非常重要,关系到你后续的创建是否成功: 12. 进入D:\migvm目录 ...