设为首页 收藏本站
查看: 1543|回复: 0

[经验分享] Aoite 系列(03)

[复制链接]
发表于 2015-7-19 13:01:16 | 显示全部楼层 |阅读模式
  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 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(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 类型。扫描的过程并不是一次性全部加载。而是充分利用 yield 进行懒加载,第一次扫描至多返回 10 条数据(可以干涉需要返回的数量),再填充到 Queue 先进先出的队列中。等到队列中没有数据时,再重新扫描至多 10 条数据。直至扫描的队列为空并且下一批扫描的数据,整个扫描结束。
  Scan:返回类型 IEnumerable,以下代码输出内容: 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。
  

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,以下代码输出内容 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,代码可以参考 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  
{
  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 一下 :)

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-88291-1-1.html 上篇帖子: 深入剖析 redis 主从复制 下篇帖子: Redis学习笔记~Redis主从服务器,读写分离
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表