对于很多嵌入式数据库来说都有对于的内存数据库模式,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. Spark2.0编译

    Spark2.0编译 1 前言 Spark2.0正式版于今天正式发布,本文基于CDH5.0.2的Spark编译. 2 编译步骤 #2.1 下载源码 wget https://github.com/ap ...

  2. JavaScript权威指南阅读笔记3

    第六章 对象 1.首先是先介绍了对象直接量的格式:对象直接量就是1.由若干个名/值对组成的映射表,2名/值对中间由冒号分割,3名值对之间由逗号分割,4整个映射表由花括号括起来.这样就组成了一个对象直接 ...

  3. dede调用指定栏目的标签

    {dede:type typeid='1'} <a href="[field:typelink /]">[field:typename /]</a> {/d ...

  4. im命令合集

    命令历史 以:和/开头的命令都有历史纪录,可以首先键入:或/然后按上下箭头来选择某个历史命令. 启动vim 在命令行窗口中输入以下命令即可 vim 直接启动vim vim filename 打开vim ...

  5. robot自动化测试(一)---安装

    1.安装python 百度搜索安装程序即可:我安装的python 2.7.6 64位 2.安装wxpython 版本:wxPython2.8 下载地址:http://sourceforge.net/p ...

  6. linux curses函数库

    fedora20,安装yum install ncurses-devel 编译时:-lncurses 头文件:#include<curses.h> 参考:man ncurses \linu ...

  7. 数塔(dp)

    数塔 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submissi ...

  8. 论JS的重要性

    最近有学习了JavaScript,学习的过程中发现js对于前端工程师来说可以是最终要的一部分. 个人认为js就是一门语言,如果把前端比作一个人的身体,那么html就是一个人的结构,css就是这个人长的 ...

  9. Maven的使用--安装

    Maven是一个java工具,所以在安装maven之前,先确保已经安装JDK. 1.下载maven3,最新版本是Maven3.2.1 ,下载地址:http://maven.apache.org/dow ...

  10. WPF实现毛玻璃效果

    1和2需要Microsoft.WindowsAPICodePack.Shell.dll 和引用using System.Windows.Interop,并只能在有DwmApi.dll 版本的Windo ...