读书人

【散300分】由 EXtremeDB 想到的扯淡“

发布时间: 2012-03-15 11:50:39 作者: rapoo

【散300分】由 EXtremeDB 想到的扯淡“技术”——示例如何自己编写内存数据库.
我曾经写过一点短文来介绍如何编写ORM接口以及实现接口,甚至还包括触发器等。今天正好看到了介绍 EXtremeDB 等的文章,于是想到给我们死水一潭的 csdn 提供一份扯淡文章,借助我以前介绍的 ORM 接口来让我们的 .net 程序员感受一下如何开始实现一个不一样的DAL。

好了,先写出 DAL 的接口规范:

C# code
using System;using System.Linq;namespace MyName{    public interface IDomain : IDisposable    {        IQueryable<T> Cast<T>() where T : class;        void Activate<T>(T obj);        void Save<T>(T obj);        void Delete<T>(T obj);        void Commit();        void Rollback();    }}


一个数据库操作就这几条功能,包括用来查询的Cast方法,用来更新数据的Save和Delete方法,用来指挥事务结束的Commit和Rollback方法!而Active操作是为了完成延迟加载关联对象使用的,如果你(像大多数人一样)从来没有想过从数据库读取对象要延迟加载一些关联对象,那么你可以从来不去实现它。

我们这个示例的目的是要自己打造一个“内存数据库”实现。我们的asp.net等服务程序中经常要跨程序,甚至跨线程地使用许多缓存数据,有时候我们不是简单地创建一个 private static List<object> 类型的变量来保存全局对象数据库,而是使用更像一个数据库的实现方式,或许更好。例如我就经常在我实际去用SQL Server、MySQL等来部署服务器程序之前,首先使用内存数据库(我使用一种比这里示例的更加复杂一点的实现)来快速测试。反正这些数据库 ORM 都是实现 IDomain 接口,切换它们只需要在配置文件中改一行 Assembly 定义就可以了。

说道内存数据库,可能大家已经很清楚这个 IDomain 其实实现起来很简单,不过就是把一堆数据放在一个 static 的变量中!是的,但不是全部。因为做为数据库,就要支持事务的并发控制。我们在下面就是用几行代码来实现一个 ReadCommitted 级别的控制,这个级别可以避免多个事务胡乱写数据,但是不阻止事务读数据。(如果你愿意,稍微修改以下的程序,很容易完成 Repeatable 级别的控制)

这个对象类的实现是:
C# code
public class XiaoHuiDomain : IDomain{    private static Dictionary<int, object> _datas = new Dictionary<int, object>();    public IQueryable<T> Cast<T>() where T : class    {        return _datas.Values.OfType<T>().AsQueryable();    }    public void Activate<T>(T obj)    {    }    private Dictionary<int, object> Locked = new Dictionary<int, object>();    public void Save<T>(T obj)    {        if (!Monitor.TryEnter(obj, 20000))            throw new TimeoutException();        var key = obj.GetHashCode();        if (!Locked.ContainsKey(key))            Locked.Add(key, obj);        if (!_datas.ContainsKey(key))            _datas.Add(key, obj);    }    public void Delete<T>(T obj)    {        _datas.Remove(obj.GetHashCode());    }    public void Commit()    {    }    public void Rollback()    {        throw new NotImplementedException();    }    public void Dispose()    {        foreach (var x in Locked)            Monitor.Exit(x.Value);    }}


非常非常简单的一段代码,所以所说这段代码“扯淡”——没有什么技术含量!其中很大一部分想法是用来实现事务的——可惜我懒得实现 Rollback 功能了。

下面写一段简单的测试:
C# code
class Program{    static void Main(string[] args)    {        var datas = new List<UU>();        var n = 50;        var value = Encoding.Default.GetBytes("1234567890123456");        Debug.Assert(value.Length == 16);        {            var tm = new Stopwatch();            tm.Start();            for (var x = 0; x < n; x++)            {                for (var y = 0; y < 10000; y++)                    datas.Add(new UU { dt = value });            }            tm.Stop();            Console.WriteLine("内存{0}个对象共用时{1},平均{2}条记录/秒,{3}微妙/条。", n * 10000, tm.Elapsed,                (int)((n * 10000) / tm.Elapsed.TotalSeconds), tm.ElapsedMilliseconds / 10 / n);        }        using (var dd = new XiaoHuiDomain())        {            var tm = new Stopwatch();            tm.Start();            for (var x = 0; x < n; x++)            {                for (var y = 0; y < 10000; y++)                    dd.Save(new UU { dt = value });            }            dd.Commit();            tm.Stop();            Console.WriteLine("写入{0}个对象共用时{1},平均{2}条记录/秒,{3}微妙/条。", n * 10000, tm.Elapsed,                (int)((n * 10000) / tm.Elapsed.TotalSeconds), tm.ElapsedMilliseconds / 10 / n);        }        using (var dd = new SqlDomain())        {            var tm = new Stopwatch();            tm.Start();            for (var x = 0; x < n; x++)            {                for (var y = 0; y < 10000; y++)                    dd.Save(new UU { dt = value });            }            dd.Commit();            tm.Stop();            Console.WriteLine("写入{0}个对象共用时{1},平均{2}条记录/秒,{3}微妙/条。", n * 10000, tm.Elapsed,                (int)((n * 10000) / tm.Elapsed.TotalSeconds), tm.ElapsedMilliseconds / 10 / n);        }        using (var dd = new MySQLDomain())        {            var cn = dd.Cast<UU>().Count();            UU x;            var tm = new Stopwatch();            tm.Start();            dd.Cast<UU>().ForEach(u => { x = u; });            tm.Stop();            Console.WriteLine("读取{0}个对象共用时{1},平均{2}条记录/秒,{3}微妙/条。", n, tm.Elapsed, (int)(cn / tm.Elapsed.TotalSeconds),                 tm.ElapsedMilliseconds * 1000 / cn);        }        Console.ReadKey();    }}class UU{    public byte[] dt { get; set; }} 



我没有测试并发情况下是否正常,你可以测试一下。毕竟这个 XiaoHuiDomain 类只是我今天为 csdn 写着玩的一个东西。

在实际的开发中,我们总是需要测试数据库 ORM 或者 API 的并发事务下的编程情况,来决定其功能和性能的好坏。


哦,对了,这个类的起名跟csdn的“小灰”没有关系,其实是“晓辉”,是为了纪念我15年未见的一位朋友。

[解决办法]
。了
[解决办法]
呵呵...小灰很伤心...
[解决办法]
收藏了,自己的内存数据库,速度一定很快!
[解决办法]
路过。
[解决办法]
看不懂,也没明白说什么,不过支持一下,看起来很牛
[解决办法]
sp1234收徒弟不
[解决办法]
看了一遍又一遍
[解决办法]
顶下,不知道高人能不能帮忙解决个问题
[解决办法]
看了一遍,没怎么看明白。
[解决办法]
受教

读书人网 >.NET

热点推荐