ServiceStack.Redis实践
   Redis的C#客户端我选择的是ServiceStack.Redis,相比Booksleeve redis-sharp等方案,它提供了一整套从 Redis数据结构都强类型对象转换的机制;看一个例子来了解一下ServiceStack.Redis是如何组织数据的,我们使用的实体类定义如下:

?

1
2
3
4
5
6
7
8
9
10
11 public class User
   {
       public User()
       {
           this.BlogIds = new List<long>();
       }
 
       public long Id { get; set; }
       public string Name { get; set; }
       public List<long> BlogIds { get; set; }
   }</long></long>
使用下面的代码片段,我们存入两条数据到Redis:

?

1
2
3
4
5
6
7 using (var redisUsers = redisClient.GetTypedClient<user>())
        {
            var ayende = new User { Id = redisUsers.GetNextSequence(), Name = "Oren Eini" };
            var mythz = new User { Id = redisUsers.GetNextSequence(), Name = "Demis Bellot" };
            redisUsers.Store(ayende);
            redisUsers.Store(mythz);
          }</user>
我们看下Redis中的结果:

?

1
2
3
4
5 redis 127.0.0.1:6379[1]> keys *
1) "seq:User"
2) "ids:User"
3) "urn:user:1"
4) "urn:user:2"
我们逐一检查一下数据类型:
 seq:User    
string  
维护当前类型User的ID自增序列,用做对象唯一ID
 ids:User
set       
同一类型User所有对象ID的列表
 urn:user:1
string 
user对象
seq:User 维护的是类型User的ID序列 redisUsers.GetNextSequence()

?

1
2
3
4
5
6
7
8 public long GetNextSequence(int incrBy)
  {
             return IncrementValueBy(SequenceKey, incrBy);
  }
 public long IncrementValue(string key)
    {
              return client.Incr(key);
     }
这里的SequenceKey就是 "seq:User",然后我们通过存一个对象到Redis看另外两个key是什么作用:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 public T Store(T entity)
       {
           var urnKey = entity.CreateUrn();
           this.SetEntry(urnKey, entity);
 
           return entity;
       }
       //entity.CreateUrn();的结果是"urn:user:1"
       public void SetEntry(string key, T value)
       {
           if (key == null)
               throw new ArgumentNullException("key");
 
           client.Set(key, SerializeValue(value));
           client.RegisterTypeId(value);
       }
 
       internal void RegisterTypeId<t>(T value)
       {
           var typeIdsSetKey = GetTypeIdsSetKey<t>();
           var id = value.GetId().ToString();
 
           if (this.Pipeline != null)
           {
               var registeredTypeIdsWithinPipeline = GetRegisteredTypeIdsWithinPipeline(typeIdsSetKey);
               registeredTypeIdsWithinPipeline.Add(id);
           }
           else
           {
               this.AddItemToSet(typeIdsSetKey, id);
           }
       }</t></t>  
这里的typedIdsSetKey 就是"ids:User"

ids:User相当于一个索引,包含了所有同为类型User的ID;由于维护了这样一个分组信息,所以很容易实现GetAll()这样的功能;
在redis-cli中查询一下 get urn:user:1 返回值是 JSON格式:
"{\"Id\":1,\"Name\":\"Oren Eini\",\"BlogIds\":[1]}"
 
ServiceStack.Redis 自己实现了一套序列化功能, Fastest JSON Serializer for .NET released 支持 POCO(Plain Old CLR Object)序列化.
 
   实际应用中,由于我们使用的数据是来自关系型数据库,本身包含关联关系,所以并不需要这样的对象组织方式;我们只需要把关系型数据中一对多的关系在Redis中表达出来即可;这里我扩展修改了RedisClient的实现,由于RedisClient本身已经通过 partial方式 分割成若干个文件,所以很容易把变动的代码集中在同一个代码文件中.具体业务对象存储,主帖和回帖会有字段级修改,所以设计成为Hash结构,其它几个子对象读写都是以对象为单位,设计成为POCO方式持久化;
使用管道Pipeline遇到的问题
  使用管道可以将客户端到Redis的往返次数减少,不过在使用ServiceStack.Redis的时候,遇到这样一个问题,比如要把一个List全部存储,代码不可以写成下面这样:

?

1
2
3
4
5
6
7
8
9 %%第一种写法
           logs.ForEach(n =>
                {
                    pipeline.QueueCommand(r =>
                    {
                        ((RedisClient)r).Store<oplog>(n, n.GetObjectID(), n.GetUrnKey());
                        ((RedisClient)r).Expire(n.GetUrnKey(), dataLifeTime);
                    });
                });</oplog>
而是要写成这样:

?

1
2
3
4
5
6
7
8 %%第二种写法
 logs.ForEach(n =>
                {
   
                    pipeline.QueueCommand(r => ((RedisClient)r).Store<log>(n, n.ID, n.GetUrnKey()));
                    pipeline.QueueCommand(r => ((RedisClient)r).Expire(n.GetUrnKey(), dataLifeTime));
 
                });</log>
什么原因呢?RedisQueueCompletableOperation的AddCurrentQueuedOperation方法会在
执行CurrentQueuedOperation =
null;如果按照第一种写法会丢失回调函数,这就造成有返回值在没有及时提取,后续的操作获取返回值时首先取到的是积压的结果信息,就出现了异常,而第
二种写法就避免了这个问题.
1
2
3
4
5
protected virtual void AddCurrentQueuedOperation()
      {
          this.QueuedCommands.Add(CurrentQueuedOperation);
          CurrentQueuedOperation = null;
      }

Redis基础(转)的更多相关文章

  1. windows下使用redis,Redis入门使用,Redis基础命令

    windows下使用redis,Redis入门使用,Redis基础命令 >>>>>>>>>>>>>>>> ...

  2. [.net 面向对象程序设计深入](14)Redis——基础

    [.net 面向对象程序设计深入](14)Redis——基础 很长一段时间没更新博客了,坚持做一件事,真不是件容易的事,后面我会继续尽可能的花时间更新完这个系列文章. 因这个系列的文章涉及的范围太大了 ...

  3. linux redis基础应用 主从服务器配置

    Redis基础应用 redis是一个开源的可基于内存可持久化的日志型,key-value数据库redis的存储分为内存存储,磁盘存储和log文件三部分配置文件中有三个参数对其进行配置 优势:和memc ...

  4. [.net 面向对象程序设计深入](36)Redis——基础

    [.net 面向对象程序设计深入](36)Redis——基础 很长一段时间没更新博客了,坚持做一件事,真不是件容易的事,后面我会继续尽可能的花时间更新完这个系列文章. 因这个系列的文章涉及的范围太大了 ...

  5. mysql主从复制、redis基础、持久化和主从复制

    一.mysql(mariadb)基础 1.基础命令(centos7操作系统下) 1.启动mysql systemctl start mariadb 2.linux客户端连接自己 mysql -uroo ...

  6. Redis基础用法、高级特性与性能调优以及缓存穿透等分析

     一.Redis介绍 Redis是一个开源的,基于内存的结构化数据存储媒介,可以作为数据库.缓存服务或消息服务使用.Redis支持多种数据结构,包括字符串.哈希表.链表.集合.有序集合.位图.Hype ...

  7. Redis基础知识补充及持久化、备份介绍(二)--技术流ken

    Redis知识补充 在上一篇博客<Redis基础认识及常用命令使用(一)--技术流ken>中已经介绍了redis的一些基础知识,以及常用命令的使用,本篇博客将补充一些基础知识以及redis ...

  8. Spring-Boot之Redis基础

    Spring-Boot之Redis基础 准备 Redis下载地址:github.com/MSOpenTech/redis/releases Redis数据库的默认端口号是 6379 开启Redis服务 ...

  9. mongodb,Mysql,redis基础教程

    数据库基础 1:mongodb基础教程 1:pymongo基础教程  2:Mysql基础教程 3:redis基础教程

  10. Redis基础知识点面试手册

    Redis基础知识点面试手册 基础 概述 数据类型 STRING LIST SET HASH ZSET(SORTEDSET) 数据结构 字典 跳跃表 使用场景 会话缓存 缓存 计数器 查找表 消息队列 ...

随机推荐

  1. asp.net webform 中使用Microsoft ASP.NET Web Optimization压缩js及css

    使用静态资源压缩可以合并静态资源文件减少客户端请求数量,压缩文件大小,减少网络流量的损耗. 注:只有通过web.config关闭调试功能,压缩才会生效 <system.web> <c ...

  2. Linux基础之常用命令(1)

    一 linux命令的格式 1.命令  [选项]  [参数] ls  list    显示目录下内容 ①  命令名称:ls 命令英文原意:list 命令所在路径:/bin/ls 执行权限:所有用户 功能 ...

  3. (Collection)350. Intersection of Two Arrays II

    /* Given two arrays, write a function to compute their intersection. Example: Given nums1 = [1, 2, 2 ...

  4. 下载Tomcat时Tomcat网站上的core和deployer的区别

    下载Tomcat时Tomcat网站上的core和deployer的区别 做JavaEE开发的朋友,无论是学习者还是已经工作的朋友,总是会用到Tomcat这个Servlet容器,那么大家从Tomcat官 ...

  5. 转载:ActiveMQ的可靠性机制

    1.JMS消息确认机制 JMS消息只有在被确认之后,才认为已经被成功地消费了.消息的成功消费通常包含三个阶段:客户接收消息.客户处理消息和消息被确认.在事务性会话中,当一个事务被提交的时候,确认自动发 ...

  6. 启动kafka出现找不到或无法加载主类

    首先确认下环境变量配置是否成功. 如果配置成功<javac,javah>都没有问题,那就有可能是你安装了两个版本的jdk导致的,都卸载了,然后换一个目录按照一个jdk 在配置环境变量试下!

  7. 关于Jquery中ajax介绍

    jQuery 底层 AJAX 实现.简单易用的高层实现见 $.get, $.post 等.$.ajax() 返回其创建的 XMLHttpRequest 对象.大多数情况下你无需直接操作该函数,除非你需 ...

  8. Windows 10下通过蓝牙连接iPhone个人热点进行共享上网

    出处:qiuyi21.cnblogs.com 1.iPhone开启个人热点 在iPhone中打开蓝牙,然后进入“个人热点”并打开开关,如果提示热点发射方式请选择蓝牙那项,然后停留在“个人热点”界面并且 ...

  9. js处理url参数

    var UrlArgent = { Parsed: false, //是否已解析 Cache: {}, //缓存值 ParseArg: function () { // 解析地址栏的参数值 UrlAr ...

  10. Maven构建项目后项目报Error错误Java compiler level does not match the version of the installed Java project fac

    项目->右键->Project Facets->修改facets中Java版本(下拉箭头出)为要用的版本 Maven构建项目需注意 1.项目右键->Preferences-&g ...