对于很多嵌入式数据库来说都有对于的内存数据库模式,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. Git新建本地分支与远程分支关联问题:git branch --set-upstream

    Git新建本地分支与远程分支关联问题:git branch --set-upstream git在本地新建分支, push到remote服务器上之后,再次pull下来的时候,如果不做处理会报以下提示: ...

  2. Android-------手机屏幕适配之文件适配

    public class Main {         //定义文件本地存储路径,可按照需求更改         private final static String rootPath = &quo ...

  3. (转) mac 下的eclipse 配置 python 2.7

    原地址: http://marsfreewill.blogspot.it/2012/08/mac-ospythonpydeveclipse.html   在MAC OS上配置Python开发环境(Py ...

  4. 通过startup启动tomcat一闪而过的问题

    下载了免安装版的tomcat7,在通过startup.bat启动时,控制台一闪而过.记事本讲startup.bat打开,在最后一行加上pause,然后重新双击startup.bat,发现控制台打印的错 ...

  5. No.1_1 java语言基础_学习笔记

    import java.util.Scanner; public class HelloWorld { static final double PI=3.14; static int x=125; / ...

  6. 转:Linux中find命令-path -prune用法详解

    在Windows中可以在某些路径中查找文件,也可以设定不在某些路径中查找文件,下面用Linux中的find的命令结合其-path -prune参数来看看在Linux中怎么实现此功能. 假如在当前目录下 ...

  7. Flask的session——关于写扩展所学习到的

    这两天端午节.趁着端午节没事干,写了个flask的扩展--flask-RedisSession 在flask中使用该扩展可以让你借助redis数据库轻松获得server-side session. 这 ...

  8. 系统service

    Context.TELEPHONY_SERVICE TelephonyManager tManager = (TelephonyManager)getSystemService(Context.TEL ...

  9. HttpApplication中的异步线程

    一.Asp.net中的线程池设置 在Asp.net的服务处理中,每当服务器收到一个请求,HttpRuntime将从HttpApplication池中获取一个HttpApplication对象处理此请求 ...

  10. WPF笔记(1.1 WPF基础)——Hello,WPF!

    原文:WPF笔记(1.1 WPF基础)--Hello,WPF! Example 1-1. Minimal C# WPF application// MyApp.csusing System;using ...