对于很多嵌入式数据库来说都有对于的内存数据库模式,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. NET基础课--泛型(NET之美)

    1.泛型,类型或方法的一种抽象概括. 2.泛型类:在类型名后面加一个<>,其中传递占位符,也就是类型参数.where是类型约束 可以再查资料 public class SortHelper ...

  2. (转)SQL Server 触发器

    SQL Server 触发器 触发器是一种特殊类型的存储过程,它不同于之前的我们介绍的存储过程.触发器主要是通过事件进行触发被自动调用执行的.而存储过程可以通过存储过程的名称被调用. Ø 什么是触发器 ...

  3. ASP.NET MVC:自定义 Route 生成小写 Url(转)

    先给出本文中测试用的 controller: public class PersonsController : Controller { public ActionResult Query(strin ...

  4. C++单链表的创建与操作

    链表是一种动态数据结构,他的特点是用一组任意的存储单元(可以是连续的,也可以是不连续的)存放数据元素.链表中每一个元素成为“结点”,每一个结点都是由数据域和指针域组成的,每个结点中的指针域指向下一个结 ...

  5. OpenSSl编译

    1.下载openssl代码,下载地址:http://www.openssl.org/source/ ,如果使用winrar解压失败的话(提示不能创建符号链接),可以关闭UAC.2.下载安装Active ...

  6. SQL语句 计算某段时间工作日的天数(除了周六日)

    --只是加了固定日期,可以根据需求给成变量形式(BY 少年工藤) -思路:根据日期区间循环判断每一天是周日(1).周六(7)不变,其他加1 1 DECLARE @DAY DATE,@COUNT INT ...

  7. ExtJs 学习笔记

    1.显示中文  <script type="text/javascript" src="../../locale/ext-lang-zh_CN.js"&g ...

  8. jQuery中的$.extend方法总结

    原文见:jQuery.extend()函数详解 Jquery的扩展方法extend是我们在写插件的过程中常用的方法,但是经常容易搞不清楚以下两个写法的关系: 1.$.extend(dest,src1, ...

  9. spring3+hibernate3+(dbcp+oracle+拦截器事务配置)整合(一)

    1.applicationContext-base.xml文件 <?xml version="1.0" encoding="UTF-8"?>< ...

  10. 【转】nginx之逻辑运算

    nginx的配置中不支持if条件的逻辑与&& 逻辑或|| 运算 ,而且不支持if的嵌套语法,否则会报下面的错误:nginx: [emerg] invalid condition. 我们 ...