提高生产性工具(四) - XML数据库的尝试

首先祝大家新年快乐.身体健康,平安就是福气.

对于一般的个人迷你项目,数据量不大的时候,完全没有必要使用数据库,管理数据使用XML就可以了.

自己尝试写了一个XML数据库,插入1w条小记录,大概3M大小,然后将一半数据进行更新,大约耗时3秒钟.

XML数据库其实就是一个内存数据库,数据都在内存里面,速度不慢.

然后由于是XML序列化的,其实ORM也不需要了.每个数据库文件保存一种格式的数据.

废话不说,上代码

先是数据模型:

/*
 * Created by SharpDevelop.
 * User: scs
 * Date: 2014/12/30
 * Time: 14:07
 *
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using DevKit.Common;
namespace DevKit.HtmlUtility
{
    /// <summary>
    /// Description of Class1.
    /// </summary>
    [Serializable]
    public class CodeSnap
    {
        /// <summary>
        /// 标题
        /// </summary>
        public string Title = string.Empty;
        /// <summary>
        /// 描述
        /// </summary>
        public string Descrpition = string.Empty;
        /// <summary>
        /// 类别
        /// </summary>
        public string Catalog = string.Empty;
        /// <summary>
        /// Tag
        /// </summary>
        public string Tag = string.Empty;
        /// <summary>
        /// 代码
        /// </summary>
        public string Code = string.Empty;
        /// <summary>
        /// 检索
        /// </summary>
        /// <param name="strKeyword">检索关键字</param>
        /// <returns></returns>
        Boolean Search(string strKeyword)
        {
            return false;
        }

    }
}

数据模型是领域的数据,但是删除标志,更新时间这些数据库使用的字段也是需要的.由于需要序列化,必须打上[Serializable]

    /// <summary>
    /// 数据库记录
    /// </summary>
    [Serializable]
    public class Model<T>
    {
        /// <summary>
        /// 删除标志
        /// </summary>
        public Boolean IsDel;
        /// <summary>
        /// 统一编号
        /// </summary>
        public string DBId;
        /// <summary>
        /// 最后更新时间
        /// </summary>
        public DateTime LastUpdate;
        /// <summary>
        /// 数据
        /// </summary>
        public T DataRec;
    }

最后是数据库引擎的代码,这里用到了深拷贝

    /// <summary>
    /// 数据库引擎
    /// </summary>
    public class XmlDataBase<T>
    {
        /// <summary>
        /// 数据库状态
        /// </summary>
        public string Status = "Close";
        /// <summary>
        /// 数据表
        /// </summary>
        List<Model<T>> list = new List<Model<T>>();
        /// <summary>
        /// 数据库文件
        /// </summary>
        string DBfilename = string.Empty;
        /// <summary>
        /// 数据库记录数[Without IsDel]
        /// </summary>
        /// <returns></returns>
        public int getCount()
        {
            return list.Count(x => {
                return !x.IsDel;
            });
        }
        /// <summary>
        /// 数据库记录数[With IsDel]
        /// </summary>
        /// <returns></returns>
        public int getCountWithDel()
        {
            return list.Count;
        }
        /// <summary>
        /// 新建并且打开数据库
        /// </summary>
        /// <param name="xmlfilename"></param>
        public XmlDataBase(string xmlfilename)
        {
            DBfilename = xmlfilename;
            if (System.IO.File.Exists(xmlfilename)) {
                list = Utility.LoadObjFromXml<List<Model<T>>>(DBfilename);
            }
        }
        /// <summary>
        /// 压缩数据库
        /// </summary>
        public void Compress()
        {
            var Compresslist = new List<Model<T>>();
            Func<Model<T>,Boolean> inner = (x) => {
                return (!x.IsDel);
            };
            Compresslist = list.FindAll(new Predicate<Model<T>>(inner));
            list = Compresslist;
            Commit();
        }
        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="rec"></param>
        public void AppendRec(T rec)
        {
            var dbrec = new Model<T>();
            dbrec.DBId = Guid.NewGuid().ToString();
            dbrec.DataRec = Common.Utility.DeepCopy(rec);
            dbrec.LastUpdate = DateTime.Now;
            list.Add(dbrec);
        }
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="rec"></param>
        public void DelRec(Model<T> rec)
        {
            rec.IsDel = true;
            UpdateDB(Utility.DeepCopy(rec));
        }
        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="rec"></param>
        public void UpdataRec(Model<T> rec)
        {
            UpdateDB(Utility.DeepCopy(rec));
        }
        /// <summary>
        /// 数据的修改
        /// </summary>
        /// <param name="rec">传递过来对象的深拷贝</param>
        void UpdateDB(Model<T> rec)
        {
            for (int i = 0; i < list.Count; i++) {
                if (rec.DBId == list[i].DBId) {
                    rec.LastUpdate = DateTime.Now;
                    //不允许内部数据使用外部数据的指针引用
                    //这里使用深拷贝
                    list[i] = rec;
                    break;
                }
            }
        }
        /// <summary>
        /// 提交更新
        /// </summary>
        public void Commit()
        {
            Utility.SaveObjAsXml(DBfilename, list);
        }
        /// <summary>
        /// 检索
        /// </summary>
        /// <param name="SearchMethod"></param>
        /// <returns>数据对象的深拷贝</returns>
        public List<Model<T>> Search(Func<T,Boolean> SearchMethod)
        {
            Func<Model<T>,Boolean> inner = (x) => {
                return (SearchMethod(x.DataRec) && !x.IsDel);
            };
            List<Model<T>> t = new List<Model<T>>();
            foreach (Model<T> element in list.FindAll(new Predicate<Model<T>>(inner))) {
                //这里也是将数据的副本给与外部
                t.Add(Utility.DeepCopy(element));
            }
            return t;
        }
    }

数据库内部有一个列表,列表里面存放着数据记录,每个数据记录包括[业务数据]和[数据库信息]

数据的读取,给外部的是一个数据的深拷贝,这样的话,保证了外部对于数据的修改不会影响内部数据.

在传统的数据库中,一般都是通过TCP协议交换数据的,所以,数据其实也是一个深拷贝.

读取如此,保存数据也是将列表替换为一个外部对象的深拷贝.

每次保存数据的时候,其实是将所有的数据都写入数据XML文件中,当然,数据量少的前提下,这样做是可以的.

下面是一个使用的例子:数据库的New语句

            Common.XmlDataBase<CodeSnap> db= new Common.XmlDataBase<CodeSnap>(@"C:\中和软件\CodeSnap.xml");;
        void BtnAppendClick(object sender, EventArgs e)
        {
            Stopwatch x = new Stopwatch();
            x.Start();
            for (int i = 0; i < 9999; i++) {
                var r = new CodeSnap();
                r.Title = "Title" + i.ToString();
                r.Descrpition = "Descrpition";
                r.Tag = "Tag";
                r.Code = "Code";
                db.AppendRec(r);
            }
            db.Commit();
            var t = db.Search((m) => {
                return true;
            });
            for (int i = 0; i < t.Count; i++) {
                if (i % 2 == 1) {
                    t[i].DataRec.Title = "New Title";
                    db.UpdataRec(t[i]);
                }
            }
            db.Commit();
            x.Stop();
            MessageBox.Show(x.Elapsed.ToString());
        }

这个只是一个XML数据的雏形,原代码基本上都在这里了.

可以改进的地方大概如下:NameSpace这些XML特有的属性的去除.

<ArrayOfModelOfCodeSnap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

现在Key是用GUID的,这个东西也蛮大的,如果不考虑压缩数据库的问题,可以使用数字连番.

(如果使用数字连番的话,由于压缩数据库会改变数据记录数,可能出现主健重复的问题)

其他压缩,例如时间,现在使用标准的DateTime.Now,所以时间也很冗长.以后可以将时间格式化后,保存为文字列.

    <IsDel>false</IsDel>
    <DBId>ef65bff8-4951-464d-bd8f-432f1148b9f8</DBId>
    <LastUpdate>2014-12-31T11:02:43.5750566+08:00</LastUpdate>

当然,XML也可以换成JSON的,这样的话,数据可以更小,但是JSON操作还不是NET内置的功能,所以暂时不使用.

里面用到的XML操作和深拷贝代码如下

        }
        /// <summary>
        /// 保存对象
        /// </summary>
        public static void SaveObjAsXml<T>(string filename, T Obj)
        {
            var xml = new XmlSerializer(typeof(T));
            var writer = new StreamWriter(filename);
            xml.Serialize(writer, Obj);
            writer.Close();
        }
        /// <summary>
        /// 读取对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filename"></param>
        /// <returns></returns>
        public static T LoadObjFromXml<T>(string filename)
        {
            var xml = new XmlSerializer(typeof(T));
            var reader = new StreamReader(filename);
            T obj = (T)xml.Deserialize(reader);
            reader.Close();
            return obj;
        }
        /// <summary>
        /// 深拷贝
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T DeepCopy<T>(T obj){
            BinaryFormatter bFormatter = new BinaryFormatter();
            MemoryStream stream = new MemoryStream();
            bFormatter.Serialize(stream, obj);
            stream.Seek(0, SeekOrigin.Begin);
            return (T)bFormatter.Deserialize(stream);
        }
时间: 2024-09-30 09:36:33

提高生产性工具(四) - XML数据库的尝试的相关文章

提高生产性工具 - Model代码生成器(NET / JAVA) (一)

原来在上一家公司,整整一年都在做工具,提高生产性,那个项目特别巨大,所以总共为老东家节约了500K左右的美金. (除了表扬之外,我个人什么好处都没有,领导们都升官发财了,郁闷) 到了新公司,也准备开发一些提高生产性的工具.最近在看NET MVC和Spring MVC的资料.所以想开发一个Model代码生成工具. 公司不能上Git,代码也刚开始写,所以暂时不拿出来了.逻辑很简单,博客园高手如云,看一下就知道我怎么写的了. 功能现在还很简单,以后完善. 软件的界面大概是这个样子的,验证这块只是开了个

提高生产性工具 - 各种工具的集成(三)

这周学习了一下Struts2的一些知识,按照网络上各种博文的指点,跌跌撞撞,捣鼓出了一个Struts2的Demo了. 原来一直是学习NET的,一下子开始玩Java的东西,还需要一点时间来适应Eclapse. Struts的Jar包导入都是依靠Maven进行的,据说Maven可以直接生成Struts的工程,尝试了一下,公司网络不给力,没有成功. Struts的Helloworld环境配置,网络上有很多文章了,这里也不多唠叨了.有一点请注意, 如果你使用Maven的话,在百度上检索 Maven St

通过mybatis工具generatorConfig.xml自动生成实体,DAO,映射文件

简介 Mybatis属于半自动ORM,可以利用mybatis工具generatorConfig.xml自动生成DAO.实体.映射文件的方式来代替手动书写的方式,这样既提高了工作效率也可以在项目避免出现的一些细微难调试的BUG. 前提条件: 1.需要准备的第三方jar包为: mybatis-generator-core-1.3.2.jar和mysql-connector-java-5.1.39-bin.jar, 其中mybatis-generator-core-1.3.2.jar的下载地址为: h

高级数据库设计与应用 05 - XML数据库建模

一.实验目的 本实验关键之处在于,要求训练并掌握书写数据库设计文档的能力, 并且能利用学过的XML数据库进行模式的创建,实现学而致用的习惯. 同时,也要求梳理实验中所涉及到的实验重点和难点知识,即:XML数据库模式的设计和XML结构体系,要求在把数据存储形式转变为XML形式后,形成自己的关于XML数据库模式设计和创建的相关知识体系. 二.实验内容 实验背景导入: 某公司接到一个网购系统的项目,任命你做该任务的数据库设计师,对网购系统进行数据库整体的设计.Webshop就是一个B2C模式的电子商城

SCCM 2012 R2 实战系列(四)—数据库及必要组件安装

下面来介绍其余的组件,SCCM是需要数据库支持的,因此必须在SCCM服务器上首先将数据库安装好,另外SCCM部署中需要用到ADK中的部署工具,我们还需要在SCCM中安装Windows ADK 8.1,在部署过程中通过SCCM部署客户端计算机需要用到WDS组件,另外我们还需要配置IIS,这些都是提前需要准备好的,下面来介绍安装配置方法,首先是数据库的安装 这里一定要注意: SCCM不支持Express版本的数据库,数据库必须要打SP补丁,否则SCCM将无法正常识别,另外数据库如果是SQL 2012

Laravel教程 四:数据库和Eloquent

Laravel教程 四:数据库和Eloquent 此文章为原创文章,未经同意,禁止转载. Eloquent Database 上一篇写了一些Laravel Blade的基本用法和给视图传递变量的几种方式, 这一节我们来说说跟数据库打交道的数据库配置和Laravel强大的Eloquent. Laravel的数据库配置 本部分内容为下节做准备 Laravel的配置文件都是在项目目录的config/文件夹之下,这里也就是在blog/config文件夹之下,你可以打开这个文件夹看看,你面有很多配置文件:

java读取中文分词工具(四)

import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.RandomAccessFile; import java.io.Serializable; import java.util.ArrayList; import java.ut

一个C#的XML数据库访问类

原文地址:http://hankjin.blog.163.com/blog/static/33731937200942915452244/ 程序中不可避免的要用到配置文件或数据,对于数据量比较小的程序,部署数据库花费的时间就显得浪费了,因此用XML来存储不妨为一个很好的办法,而且结合C#的DataSet,我们可以很轻易的封装出一个代码简单而功能强大的数据访问类XMLConfigconfig.xml<root>  <table1>    <rowName1>hello&l

[解决办法]windows的非administrator账户无法通过plsql工具登录oracle数据库

环境:windows2008服务器.使用的非administrator账户,而是新建了一个windows2008账户.安装好了plsql工具. 问题:使用administrator账户可以用plsql工具连接成功oracle数据库:但是使用非administrator账户用plsql工具连接oracle数据库失败,如下图: 原因:经过反复排查,是因为plsql工具没有获取系统的权限,而且加入了administrators组也是无效,主要原因是windows在vista系统之后新增了一个UAC(用