时间:2016-12-9来源:本站原创作者:佚名

Rdis是内存数据库,在很多地方中,是作为关系型数据库的缓存来使用的,类似MmoryCach。

它支持存储的valu类型相对更多,包括string(字符串)、list(链表)、st(集合)、zst(sortdst--有序集合)和hash(哈希类型),rdis的出现,很大程度补偿了mmcachd这类ky/valu存储的不足,在部分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Prl,Objct-C,Python,Ruby,Erlang等客户端,使用很方便。

但Rdis也有持久化的功能,所以有的地方也会抛弃关系型数据库直接使用Rdis。

比如开发一个网站,有些频繁更新的数据,使用关系型数据库会不太合适。遇到这种情况,通常,可以自己做一层内存缓存或者使用其他的缓存工具。

自己做内存缓存的话,那么数据就被锁定在缓存它的进程中了,如果是分布式系统,就不好同步。而放在Rdis之类的内存数据库中的话,需要通过通信交互才能获得数据。

两种方式各有利弊,抛开这层不谈,直说使用Rdis的情况,假设有这样一款应用使用Rdis作为数据容器,作为一个基础应用的案例,一步步体验Rdis中的功能,最后封装出一个方便使用Rdis存取的类库,就是本文的内容了。

首先这个应用是数据相关的,也就没有了界面,可以当做是Wb后端,或者是网络游戏的游戏服务器部分。因为是只处理数据,所以不引入网络通信,只是假设有这样一个入口,能够接收符合接口的各种输入。

我就直接设定这是一个游戏,语言使用的是C#。

一使用VS创建解决方案

包含两个项目,一个ConsolApplication名为RdisTst,一个类库RoyEngin,RdisTst添加项目引用RoyEngin。RoyEngin就是目标封装的Rdis的快速使用类库了。

二创建类Playr

作为一个数据应用,第一步,是要能保存数据,最先的数据就是用户信息。所以我首先在RdisTst中创建一个类Playr。

非常简单,只有名字和战斗力两个属性。

然后在Main函数中varplayr=nwPlayr();并给属性赋值。

我的目的是要把这个playr实例保存到Rdis中去。

所以我需要这样一个方法,Sav(playr);

三添加Rdis快速访问类Roy

在RoyEngin中创建classRoy,添加函数voidSavT(Tntity)

毫无疑问,这必须是一个泛型函数。感觉有点像是关系型数据库的ORM。

现在实现这个函数就需要连接Rdis,这里需要说明的是Rdis读写是单线程的,也就是说不管创建几个连接,数据到了Rdis都会依序读写,所以,Roy并不会创建多个对Rdis的连接。

四连接Rdis

C#对Rdis的对接已经有很多类库了,通过NuGt搜索Rdis,你将看到一堆如StackExchang.Rdis、SrvicStack.Rdis等等,这里我使用的是SrvicStack.Rdis的V3版本,因为之后的V4是要收费的,所以分出了一个分支叫NSrvicKit.Rdis,可以在GitHub上找到它的源码。

这里通过Nugt安装到RoyEngin中,点开引用,可以看到如下图:

增加了4个引用,值得一提的是其中的NSrvicKit.Txt其实是有JSON功能的。

有了这个类库,就可以给Roy添加一个私有字段RdisClint_rdis;

然后在构造函数中传入host,port,password和db四个参数,并对_rdis进行实例化了。

我重载了两个构造函数,做完这一步,可以到RdisTst项目的Main函数中添加对应实例化的代码

Royroy=nwRoy(“localhost”,);

那么Rdis的连接就告成了。

五实现SavT()函数

其实对这个Sav的实现有一个很简单方式,就是直接Json序列化保存。

Rdis是一个键值对数据库,存取都是通过键值对匹配的方式,只要有一个Id作为Ky就能保存各种各样的数据。

上面提及过,NSrvicKit.Txt其实是带有JSON功能的,所以,如果只想使用JSON保存,可以直接使用_rdis.St(id,ntity);就搞定了。

这里使用的St是对应rdis的SET命令,对应的读取命令是Gt,也有对应的函数实现。

NSK.Rdis在St时会对ntity自动json序列化保存。

当然我不这么做,Rdis有一个结构叫做Hash,本身具有一个键,而保存的值类型是键值对的Hash表,非常适合做这种实例的浅序列化(只保存一层基础类型)。

那么Id怎么获取呢?

Rdis有一个incr的命令,其实就是维护一个ky对应的incrmnt值。把这个ky设定为classNam,那么每一个class获取到的自增值肯定都隔离了。

在自增的下,设定实例的Id={ClassNam}:{incrId},那就可以保证每一个保存的class实例都是唯一的了。

有了Hash的Id,就可以对这个Hash进行HMSt命令了,这个命令是HSET的multi版,可以设置多个kyValu对。

通过typOf(T).GtProprtis()获得属性,然后通过ProprtyInfo.GtValu()获得属性值,进行设置保存。

由于这里获得的所有valu都是objct的,而HashSt需要的是byt[],这里就需要转换为字节数组。其实,因为只是浅保存,所以只支持几个基本数据类型,可以设定一个支持的基本类型枚举,然后分别ConvrtToByts,最后保存到一个byt[][]中,一口气进行HMSt。

六优化

上面部分主要是反射的应用。当然反射是比较伤性能的,不过也有部分可以优化的地方,比如GtProprtis。

因为所有需要保存的类,在编译的时候肯定是可以确定了的,所以,在写代码的时候就可以加上一些标记,那么可以使用C#的Attribut特性。

我想过给Class打上一个特性来标识它是需要被存档的。但是之后,实际编写的时候发现还有一个Id这个大头的东西很重要。每一个需要存档的Class都需要一个Id,而这个Id在刚才被我设定成了string类型。那么仅仅是特性的约束就不太够了,干脆就做成基类好了。

所以,就有了这么一个基类RoyDataBas。只有继承自RoyDataBas的类型才能被保存。

那就给刚才的Sav泛型加上whrT:RoyDataBas的约束吧。

然后还可以写一个静态方法,在程序启动时执行,反射出所有RoyDataBas的子类和他们的Proprtis,保存到一个Dictionary里面,那么下次至少这部分不需要反射了。实际测试一下,做了这个之后,Sav的速度提高了一倍。

七忽略那些不需要保存的字段属性

有时候为了方便,会在需要持久化的域类型中添加一些其他的属性或字段,而这些是不需要保存也不想被保存的,那么需要给他们打上标记。那就干脆给想保存的打上标记吧。

于是增加RoyValuAttribut这个特性,在程序初始化反射的时候忽略那些不带该特性的ProprtyInfo。现在的Playr就像这样:

八读取

既然保存了,也就需要有相应的读取,同样的读取也是一个泛型方法:

publicTGtT(id)whrT:RoyDataBas,nw(){

Tt=nwT();

//读取Rdis

//找到初始化时保存好的元数据,用ProprtyInfo.StValu()方法进行赋值

}

这里读取Rdis需要用到的是Hash的另一个命令HMGt,全部读取之后遍历反射赋值,这个函数也就实现完毕了。

九测试

终于到了最后一步,实验下刚才完成的两个函数吧。哦,对了,Rdis还没有吧。

可以在我最下方提供的链接里面找到rdis的文件夹,里面有两个cmd文件,双击其中的srvr.cmd就能运行一个rdis实例。

运行起rdis之后,就在RdisTst的Main函数中保存然后读取一万个不同的Playr试试看吧。

然后你还可以改一下Sav和Gt的实现,对比下用JSON保存和Hash保存的不同。

当然也可以改成sqlinsrt试试,看看速度差多少。

附上代码和Rdis工具的







































北京最好白癜风正规医院
北京治疗白癜风哪里医院好

转载请注明原文网址:http://www.helimiaopu.com/cxkf/3031.html

------分隔线----------------------------