Aoite 系列(03) - 一起来 Redis 吧!
Aoite 是一个适于任何 .Net Framework 4.0+ 项目的快速开发整体解决方案。Aoite.Data 适用于市面上大多数的数据库提供程序,通过统一封装,可以在日常开发中简单便捷的操作数据库。
赶紧加入 Aoite GitHub 的大家庭吧!!
插几句话:开源对我来讲,是一种分享。没有人可以从中获取金钱上的利益。每一套框架都有不足和亮点所在。Aoite 目的是让园友多一种可尝试的选择。对我来说的根本目的在于让 Aoite 真正的成为一个快速开发整体解决方案。
1. 快速入门
Redis 在 .NET 上有非常多成熟的框架。Aoite.Redis 仅仅目前只是实现其中的一员。实现 Aoite.Redis 的根本目的是为了迎合 Aoite.CommandModel 模块,并且减少对外部框架的依赖。
using(var client = new RedisClient(6379, null /* password*/))
{client.FlushAll();client.Set("Int32Value", 1);client.Set("StringValue", "a");client.Set("DoubleValue", 1.0);client.Set("DecimalValue", 1.0m);client.Set("AnonymousValue", new BinaryValue(new { A = "a" }));Console.WriteLine((Int32)client.Get("Int32Value"));Console.WriteLine((String)client.Get("StringValue"));Console.WriteLine((Double)client.Get("DoubleValue"));Console.WriteLine((Decimal)client.Get("DecimalValue"));Console.WriteLine(client.Get("AnonymousValue").ToModel());
}
1.1 二进制值 BinaryValue
System.BinaryValue
是一个非常有趣的类。它提供了从 decimal、Guid、string、DateTime、DateTimeOffset、TimeSpan、bool、ulong、char、uint、double、ushort、short、float、int 和 long 与 byte[] 之间的隐式转换。
比如你可以这么写:
BinaryValue value1 = 5;
BinaryValue value2 = "abc";int x = value1;
string y = value2;
当然了,对于复杂的类型,就必须通过构造函数来创建。
BinaryValue value = new BinaryValue(new { Username = "username", Passowrd = "passowrd" });Console.WriteLine(value.ToModel());
ToModel
还提供了一个泛型,可以执行返回值的数据类型。
不过,当遇见一个你无法预期判断出具体类型时,你可以这么做:
static void Print<T>(T obj)
{BinaryValue value = BinaryValue.Create(obj);Console.WriteLine(value.Parse(typeof(T)));
}
然后你就可以像这样调用:
Print("a");
Print(1);
Print(new { Username = "username", Passowrd = "passowrd" });
相信看到这里的你,应该就明白 System.BinaryValue
在 Redis 中可发挥的重大作用了。
1.2 事务
Redis 的事务不同于关系型数据库的事务。在事务范围内的任何命令,都只会返回一个内容“QUENED”,表示此命令已成功加入命令列表(但不代表执行一定会成功)。所以在 Redis 上的事务,我们要一种稍微奇怪的方式进行。
你看见的代码,可能是这样的:
using(var client = new RedisClient(6379, null /* password*/))
{using(var tran = client.BeginTransaction()){tran.On(tran.Set("key1", "value1"), r =>{Console.WriteLine("设置 Key1 为 value1 的结果是 {0}", r);});tran.On(tran.IncrBy("key2"), r =>{Console.WriteLine(r);});tran.Commit();}Console.WriteLine((string)client.Get("key1"));Console.WriteLine((string)client.Get("key2"));//- 根据 Redis 的协议,返回应该是 String 类型,而不是 Int64
}
1.3 Hash 的改进
如果有一个对象,你想存储在 Redis 中时,是以字段进行存储的,那就需要用到 Redis 的 HASH。
class MyModel
{public string Username { get; set; }public string Password { get; set; }
}
以下代码将 MyModel
存储到 Hash 中、从 Hash 获取所有域和获取部分域:
using(var client = new RedisClient(6379, null /* password*/))
{client.FlushAll();string key = "model001";client.HMSet(key, new MyModel() { Username = "admin", Password = "123456" });var model = client.HGetAll<MyModel>(key);Console.WriteLine("Model -> {0}\t{1}", model.Username, model.Password);Console.WriteLine("Username : {0}", client.HGet(key, "Username"));Console.WriteLine("Password : {0}", client.HGet(key, "Password"));
}
上面的代码输出:
Model -> admin 123456
Username : admin
Password : 123456
1.4 Scan Redis 的扫描
Redis 中有 SCAN、HSCAN、SSCAN 和 ZSCAN 四个扫描的命令。Aoite.Redis 针对扫描的命令进行封装,返回一个 IEnumerable<T>
类型。扫描的过程并不是一次性全部加载。而是充分利用 yield
进行懒加载,第一次扫描至多返回 10 条数据(可以干涉需要返回的数量),再填充到 Queue
先进先出的队列中。等到队列中没有数据时,再重新扫描至多 10 条数据。直至扫描的队列为空并且下一批扫描的数据,整个扫描结束。
Scan:返回类型 IEnumerable<string>
,以下代码输出内容: 11(1,10,11,12...18,19)。
static void Code7()
{using(var client = new RedisClient(6379, null /* password*/)){client.FlushAll();for(int i = 0; i < 20; i++){client.Set("key" + i, "Value" + i);}Console.WriteLine(client.Scan(pattern: "key1*").Count());}
}
HScan:返回类型 IEnumerable<RedisFieldItem>
。
using(var client = new RedisClient(6379, null /* password*/))
{client.FlushAll();for(int i = 0; i < 20; i++){client.HSet("Key", "Field" + i, "Value" + i);}Console.WriteLine("[Field]\t|\t[Value]");foreach(var item in client.HScan("Key", pattern: "Field1*")){Console.WriteLine("{0}\t|\t{1}",item.Field, item.Value);}
}
以上代码输出:
[Field] | [Value]
Field1 | Value1
Field10 | Value10
Field...| Value...
Field18 | Value18
Field19 | Value19
SScan:返回类型 IEnumerable<BinaryValue>
,以下代码输出内容 5。
using(var client = new RedisClient(6379, null /* password*/))
{client.FlushAll();for(int i = 0; i < 20; i++){client.SAdd("Key", "Member" + i % 5);}Console.WriteLine(client.SScan("Key").Count());
}
ZAdd:返回类型 IEnumerable<RedisScoreItem>
,代码可以参考 HScan。
1.5 哪些命令还没有被实现?
String 未实现命令
- BITCOUNT
- BITOP
- GETBIT
- SETBIT
- SETEX 、PSETEX、SETNX:因为 SET 命令可以通过参数来实现这三个命令的效果。
Key 未实现命令
- MIGRATE
- OBJECT
- DUMP
- RESTORE
Pub/Sub 未实现命令
- 所有命令等找到合适的方式再去实现。
Connection
- ECHO
Server
- ClientPause
- Monitor
- DEBUG OBJECT
- DEBUG SEGFAULT
- ROLE
- SHUTDOWN
- PSYNC
- SLAVEOF
- SLOWLOG
- SYNC
- TIME
隐式实现的命令
Transaction
,事务性命令通过IRedisClient.BeginTransaction
来隐士完成。- DISCARD
- EXEC
- MULTI
Connection
- AUTH:初始化 RedisClient 就应该提供 Redis 的密码,来简化整体的流程。
3. 序列化
Aoite.Serialization 里有包含两个部分内容。
- 继承
System.Serializer
的序列化器。比如已实现好的:System.Serializer.Binary
、System.Serializer.Json
和System.Serializer.Xml
,当然还有本节的主角 `System.Serializer.Quickly'。 - 一套二进制的序列化组件
Aoite.Serialization.ObjectWriter
和ObjectReader
。这是一套针对字段级别的序列化,支持的类型非常多,Aoite.Tests 里有一个非常复杂的测试对象,想要了解它支持的类型,可以通过那个单元测试进行了解。
3.1 快速入门
我们定义一个稍微有一丝丝复杂的对象:
class Dict2 : Dictionary<string, object>
{public string MyProperty { get; set; }
}
然后我们可以这么序列化和反序列化:
Dict2 dict = new Dict2() { MyProperty = "Hello" };
dict.Add("1", new { A = "a" });
dict.Add("2", "haha");
dict.Add("3", 3);
dict.Add("4", new[] { 1, 2, 3, 4 });
var bytes = Serializer.Quickly.FastWriteBytes(dict);
Console.WriteLine("bytes length {0}", bytes.Length);var dict2 = Serializer.Quickly.FastReadBytes(bytes) as Dict2;foreach(var item in dict2)
{Console.WriteLine("{0}\t\t{1}", item.Key, item.Value);if(item.Value is Array){foreach(var value in item.Value as Array){Console.Write(value);Console.Write(","); }}
}
3.2 序列化特殊对象
在 Aoite.Redis.RedisSessionState
这个特殊类,有一个数据类型为 SessionStateItemCollection
的特殊属性,这个通过 Quickly 的序列化是没有问题的,但是在使用时,便会抛出内存错误,具体什么原因我是没有深入研究。所以,针对无法序列化的对象,特性 SerializableUsage
便排上用场。
class RedisSessionState
{//...[SerializableUsage(typeof(Serializable))]public SessionStateItemCollection Items { get; set; }//...class Serializable : Aoite.Serialization.ICustomSerializable{public object Deserialize(ObjectReader reader){SessionStateItemCollection items = new SessionStateItemCollection();var count = reader.ReadInt32();for(int i = 0; i < count; i++){var name = (string)reader.Deserialize();var value = reader.Deserialize();items[name] = value;}return items;}public void Serialize(ObjectWriter writer, object value){var items = value as SessionStateItemCollection;writer.InnerWrite(items.Count);foreach(string name in items.Keys){writer.Serialize(name);writer.Serialize(items[name]);}}}}
SerializableUsage
特性指定一个类型,这样序列化器在处理过程中,将会初始化这个类型的实例,并调用 Serialize
或 Deserialize
方法。
这样,理论上任何对象都可以序列化为文本。当然了,如果你想序列化 System.Windows.Forms.Form
(这个还是有办法的) 或者 System.Web.Page
这就比较难了……
4. 结束
关于 Aoite.Ioc 和 Aoite.Serialization 的简单介绍,就到此结束了,如果你喜欢这个框架,不妨点个推荐吧!如果你非常喜欢这个框架,那请顺便到Aoite GitHub Star 一下 :)
转载于:https://www.cnblogs.com/sofire/p/aoite_redis.html
Aoite 系列(03) - 一起来 Redis 吧!相关推荐
- Redis系列2- C#中使用Redis的示例
上一篇Redis的系列已经讲了Redis的下载.安装,接下来这一篇,主要讲使用Redis提供的 ServiceStack.Redis 这个开发库在C#项目中作为缓存服务使用的一个简单示例,废话不多话, ...
- [ 搭建Redis本地服务器实践系列三 ] :图解Redis客户端工具连接Redis服务器
原文:[ 搭建Redis本地服务器实践系列三 ] :图解Redis客户端工具连接Redis服务器 上一章 [ 搭建Redis本地服务器实践系列二 ] :图解CentOS7配置Redis 介绍了Red ...
- openresty开发系列38--通过Lua+Redis 实现动态封禁IP
openresty开发系列38--通过Lua+Redis 实现动态封禁IP 一)需求背景为了封禁某些爬虫或者恶意用户对服务器的请求,我们需要建立一个动态的 IP 黑名单.对于黑名单之内的 IP ,拒绝 ...
- openresty开发系列27--openresty中封装redis操作
openresty开发系列27--openresty中封装redis操作 在关于web+lua+openresty开发中,项目中会大量操作redis, 重复创建连接-->数据操作-->关闭 ...
- openresty开发系列26--openresty中使用redis模块
openresty开发系列26--openresty中使用redis模块 在一些高并发的场景中,我们常常会用到缓存技术,现在我们常用的分布式缓存redis是最知名的, 操作redis,我们需要引入re ...
- Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例
转载自 Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例 第1部分 ArrayList介绍 ArrayList简介 ArrayList 是一个数组队列,相当于 动态数组.与 ...
- Redis系列教程(四):Redis为什么是单线程、及高并发快的3大原因详解
Redis的高并发和快速原因 1.redis是基于内存的,内存的读写速度非常快: 2.redis是单线程的,省去了很多上下文切换线程的时间: 3.redis使用多路复用技术,可以处理并发的连接.非阻塞 ...
- Redis系列教程(六):Redis缓存和MySQL数据一致性方案详解
需求起因 在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节.所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库. 这个业务场景,主要 ...
- Redis系列教程(五):Redis哨兵、复制、集群的设计原理,以及区别
前一篇文章高并发架构系列:Redis为什么是单线程.及高并发快的3大原因详解谈了Redis高并发快的3个原因,本篇主要谈Redis的高可用,两篇合起来就可以把redis的高并发和高可用搞清楚了. 谈到 ...
最新文章
- kalilinux安装搜狗输入法
- java时间有几种格式_java解析多种时间格式
- php grid 分页,jqGrid实现前端分页
- 东枝戛古舍利佛塔群(缅三十五)
- SQL数据库学习-简单查询
- highgui基础 OpenCV trackbar
- php post 获取xml,php 获取post的xml数据并解析示例
- 网站漏洞检测针对区块链网站安全分析
- 机器学习入门学习资料推荐
- Cobertura代码覆盖率测试
- mysql数据库服务器cpu_mysql数据库服务器cpu 100%
- 机器学习(六):支持向量机(SVM)
- 参加了feedsky的博客大赛
- Oracle 设置数据库时区
- 【优化求解】基于头脑风暴优化算法BSO求解最优目标matlab源码
- 牛客 · 奇♂妙拆分
- 桌面html文件图标异常,.htm.html文件图标无法显示的解决办法
- 电脑C盘爆满了怎么办
- 鸿蒙归蝶的反弹,诛仙鸿蒙副本怎么过
- 11个相似图片搜索网站(以图找图)[转]
热门文章
- (已解决)AttributeError: ‘PrecisionRecallDisplay‘ has no attribute ‘from_predictions‘以及查看sklearn版本
- latex中\begin{verbatim}以及\verb有什么用?
- 有序回归(ordinal regression)
- 多模态AI崛起,2022年人工智能5大发展趋势
- 《Engineering》评选2021年全球十大工程成就 | 中国工程院院刊
- 世界首富太空争霸:从地上斗到天上,马斯克VS贝索斯,谁能赢
- 科学家打造全套人工神经系统 帮助瘫痪病人重新控制身体
- 清华大学教授:唐杰——深度分析:人工智能的下个十年
- 一文看懂人脸识别技术发展脉络
- 特斯拉发布Q1无人驾驶安全报告:事故增多 但还是比人类少