C#中使用Redis学习二 在.NET4.5中使用redis hash操作
摘要
上一篇讲述了安装redis客户端和服务器端,也大体地介绍了一下redis。本篇着重讲解.NET4.0 和 .NET4.5中如何使用redis和C# redis操作哈希表。并且会将封装的一些代码贴一下。在讲解的过程中,我打算结合redis操作命令一起叙述,算是作为对比吧。这样也能让读者清楚了 解,所分装的代码对应的redis的哪一些操作命令。
hash哈希表简介
这里仅仅是对哈希表作简单概念级介绍(摘自csdn),如果需要,自己去研究。
1、哈希表的概念
哈希表(Hash Table)也叫散列表,是根据关键码值(Key Value)而直接进行访问的数据结构。它通过把关键码值映射到哈希表中的一个位置来访问记录,以加快查找的速度。这个映射函数就做散列函数,存放记录的数组叫做散列表。
2、哈希表查找的时间复杂度
哈希表存储的是键值对,其查找的时间复杂度与元素数量多少无关,哈希表在查找元素时是通过计算哈希码值来定位元素的位置从而直接访问元素的,因此,哈希表查找的时间复杂度为O(1)。
如何在.NET4.0/4.5中安装redis组件?
在上一篇博文中,安装好的redis服务器端,要记得开启服务。然后再在.NET4.5(.NET4.0同理)项目中添加对redis操作的dll文件的引用。引用的步骤如下:
第一步:右键项目中的引用,选择“管理NuGet程序包”;
第二步:在搜索栏中输入“Redis client for the Redis NoSQL DB”,联机查找;如下图:
联机搜索结构中的第一个(如上图红色区域的组件,其版本号为4.0.35)就是要安装的组件了。接下来我们就继续点击“安装”按钮,进入下载组件,等下载完成后,继续选择“接受条款”,然后继续安装。安装过程中会出现下图情况:
这句红色错误的意思是我们安装的ServiceStack.Interfaces
4.0.35版本与当前的.NET4.5框架中组件不兼容。这说明我们需要降低或是提高.NET版本解决此问题。我安装的是.NET4.5,所以我只能降
低版本。降低.NET版本的方法大家应该都知道的。我就在累述一次,希望大家不要嫌烦,毕竟还有新手在。方法:右键项目文件选择“属性”==》“应用程
序”==》“目标框架”,然后选择各个版本去尝试之前的两步操作,直到可以安装为止。
我试过了,.NET4.0也会遇到同样问题,直到.NET3.5才可以。当然此时安装的ServiceStack.Interfaces
版本是1.0.0.0
,这样我们再把.NET版本恢复4.5即可使用了。,其实是变相在.NET4.0/4.5下使用redis客户端。不知道各位有没有遇到这样的问题,还是
直接拷贝别人的dll文件。当自己亲自去操作的时候,才会发现,其实就算是安装一个组件都可能会出现各种各样的问题。所以,要想了解全过程的话,我们还是
要身体力行的啊。好了,这样就说明在.NET4.5下安装好了redis client了。
实战:在项目中运用redis代码详解
这部分主要是讲解怎样连接到redis服务器。其中包含很多配置,我就用代码去说明一切了。配置文件如下代码:
1 <configSections>
2 <section name="RedisConfig" type="RedisDemo.Common.Redis.RedisConfigInfo, RedisDemo"/>
3 </configSections>
4 <RedisConfig WriteServerList="127.0.0.1:6379" ReadServerList="127.0.0.1:6379" MaxWritePoolSize="60"
MaxReadPoolSize="60" AutoStart="true" LocalCacheTime="180" RecordeLog="false"/>
在这里对RedisConfig这段配置文件的属性作下说明。
WriteServerList:可写的Redis链接地址。
ReadServerList:可读的Redis链接地址。
MaxWritePoolSize:最大写链接数。
MaxReadPoolSize:最大读链接数。
AutoStart:自动重启。
LocalCacheTime:本地缓存到期时间,单位:秒。
RecordeLog:是否记录日志,该设置仅用于排查redis运行时出现的问题,如redis工作正常,请关闭该项。
RedisConfigInfo类是记录redis连接信息,此信息和配置文件中的RedisConfig相呼应。cs代码如下:(这段代码不是我自己写的,但是我觉得应该这样设计。所以,copy了一下别人的代码。)
using System.Configuration; namespace RedisDemo.Common.Redis
{
public sealed class RedisConfigInfo : ConfigurationSection
{
public static RedisConfigInfo GetConfig()
{
var section = (RedisConfigInfo)ConfigurationManager.GetSection("RedisConfig");
return section;
}
public static RedisConfigInfo GetConfig(string sectionName)
{
var section = (RedisConfigInfo)ConfigurationManager.GetSection("RedisConfig");
if (section == null)
{
throw new ConfigurationErrorsException("Section " + sectionName + " is not found.");
}
return section;
}
/// <summary>
/// 可写的Redis链接地址
/// </summary>
[ConfigurationProperty("WriteServerList", IsRequired = false)]
public string WriteServerList
{
get
{
return (string)base["WriteServerList"];
}
set
{
base["WriteServerList"] = value;
}
}
/// <summary>
/// 可读的Redis链接地址
/// </summary>
[ConfigurationProperty("ReadServerList", IsRequired = false)]
public string ReadServerList
{
get
{
return (string)base["ReadServerList"];
}
set
{
base["ReadServerList"] = value;
}
}
/// <summary>
/// 最大写链接数
/// </summary>
[ConfigurationProperty("MaxWritePoolSize", IsRequired = false, DefaultValue = )]
public int MaxWritePoolSize
{
get
{
var maxWritePoolSize = (int)base["MaxWritePoolSize"];
return maxWritePoolSize > ? maxWritePoolSize : ;
}
set
{
base["MaxWritePoolSize"] = value;
}
}
/// <summary>
/// 最大读链接数
/// </summary>
[ConfigurationProperty("MaxReadPoolSize", IsRequired = false, DefaultValue = )]
public int MaxReadPoolSize
{
get
{
var maxReadPoolSize = (int)base["MaxReadPoolSize"];
return maxReadPoolSize > ? maxReadPoolSize : ;
}
set
{
base["MaxReadPoolSize"] = value;
}
}
/// <summary>
/// 自动重启
/// </summary>
[ConfigurationProperty("AutoStart", IsRequired = false, DefaultValue = true)]
public bool AutoStart
{
get
{
return (bool)base["AutoStart"];
}
set
{
base["AutoStart"] = value;
}
}
/// <summary>
/// 本地缓存到期时间,单位:秒
/// </summary>
[ConfigurationProperty("LocalCacheTime", IsRequired = false, DefaultValue = )]
public int LocalCacheTime
{
get
{
return (int)base["LocalCacheTime"];
}
set
{
base["LocalCacheTime"] = value;
}
}
/// <summary>
/// 是否记录日志,该设置仅用于排查redis运行时出现的问题,如redis工作正常,请关闭该项
/// </summary>
[ConfigurationProperty("RecordeLog", IsRequired = false, DefaultValue = false)]
public bool RecordeLog
{
get
{
return (bool)base["RecordeLog"];
}
set
{
base["RecordeLog"] = value;
}
}
}
}
RedisConfigInfo 类
RedisManager类主要是创建链接池管理对象的。
using System.Linq;
using ServiceStack.Redis;
using System.Collections.Generic; namespace RedisDemo.Common.Redis
{
public class RedisManager
{
/// <summary>
/// redis配置文件信息
/// </summary>
private static readonly RedisConfigInfo RedisConfigInfo = RedisConfigInfo.GetConfig(); private static PooledRedisClientManager _prcm; /// <summary>
/// 静态构造方法,初始化链接池管理对象
/// </summary>
static RedisManager()
{
CreateManager();
} /// <summary>
/// 创建链接池管理对象
/// </summary>
private static void CreateManager()
{
var writeServerList = SplitString(RedisConfigInfo.WriteServerList, ",");
var readServerList = SplitString(RedisConfigInfo.ReadServerList, ","); _prcm = new PooledRedisClientManager(writeServerList,readServerList,
new RedisClientManagerConfig
{
MaxWritePoolSize = RedisConfigInfo.MaxWritePoolSize,
MaxReadPoolSize = RedisConfigInfo.MaxReadPoolSize,
AutoStart = RedisConfigInfo.AutoStart,
});
} private static IEnumerable<string> SplitString(string strSource, string split)
{
return strSource.Split(split.ToArray());
} /// <summary>
/// 客户端缓存操作对象
/// </summary>
public static IRedisClient GetClient()
{
if (_prcm == null)
{
CreateManager();
}
return _prcm.GetClient();
} }
}
RedisManager类
实战:封装redis对哈希表操作的代码
实战中,我们操作redis最好还是要封装提炼一下的。提炼的目的是为了以后代码的重用。代码封装重用的好处我就不多说了,这个不是本次主要讨论的。下面是我所用项目中分装的代码,其中有的部分我修改过了,贴出来让大家看下。个人感觉不错:^_^
RedisOperatorBase类,是redis操作的基类,继承自IDisposable接口,主要用于释放内存。
using System;
using ServiceStack.Redis; namespace RedisDemo.Common.Redis.RedisOperator
{
public abstract class RedisOperatorBase : IDisposable
{
protected IRedisClient Redis { get; private set; }
private bool _disposed = false;
protected RedisOperatorBase()
{
Redis = RedisManager.GetClient();
}
protected virtual void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
Redis.Dispose();
Redis = null;
}
}
this._disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// 保存数据DB文件到硬盘
/// </summary>
public void Save()
{
Redis.Save();
}
/// <summary>
/// 异步保存数据DB文件到硬盘
/// </summary>
public void SaveAsync()
{
Redis.SaveAsync();
}
}
}
RedisOperatorBase 类
HashOperator类,是操作哈希表类。继承自RedisOperatorBase类,代码中有详细注释,理解起来一目了然。
using System;
using System.Collections.Generic;
using ServiceStack.Text; namespace RedisDemo.Common.Redis.RedisOperator
{
public class HashOperator : RedisOperatorBase
{
public HashOperator() : base() { }
/// <summary>
/// 判断某个数据是否已经被缓存
/// </summary>
public bool Exist<T>(string hashId, string key)
{
return Redis.HashContainsEntry(hashId, key);
}
/// <summary>
/// 存储数据到hash表
/// </summary>
public bool Set<T>(string hashId, string key, T t)
{
var value = JsonSerializer.SerializeToString<T>(t);
return Redis.SetEntryInHash(hashId, key, value);
}
/// <summary>
/// 移除hash中的某值
/// </summary>
public bool Remove(string hashId, string key)
{
return Redis.RemoveEntryFromHash(hashId, key);
}
/// <summary>
/// 移除整个hash
/// </summary>
public bool Remove(string key)
{
return Redis.Remove(key);
}
/// <summary>
/// 从hash表获取数据
/// </summary>
public T Get<T>(string hashId, string key)
{
string value = Redis.GetValueFromHash(hashId, key);
return JsonSerializer.DeserializeFromString<T>(value);
}
/// <summary>
/// 获取整个hash的数据
/// </summary>
public List<T> GetAll<T>(string hashId)
{
var result = new List<T>();
var list = Redis.GetHashValues(hashId);
if (list != null && list.Count > )
{
list.ForEach(x =>
{
var value = JsonSerializer.DeserializeFromString<T>(x);
result.Add(value);
});
}
return result;
}
/// <summary>
/// 设置缓存过期
/// </summary>
public void SetExpire(string key, DateTime datetime)
{
Redis.ExpireEntryAt(key, datetime);
}
}
}
HashOperator 类
实战:redis操作hash哈希表的增删改查
本来打算这部分把我demo中的操作代码贴出来的,想想,全是代码,看着都烦,还不如讲解一下这部分的操作对应于redis客户端操作命令呢。还有一个原因 就是,上面都已经对hash操作进行了分装,其实如果贴代码也就是调用封装的代码罢了。感觉没啥意思,相信大家都会调用。没啥好讲的。那么接下来我就说 下,上面封装的代码与客户端操作的对应关系。
Exist<T>方法:对应于redis操作的hexists。返回字段是否是 key 指定的哈希集中存在的字段。true:存在 false:不存在
Set<T>方法:对应于redis操作的hget。设置 key 指定的哈希集中指定字段的值。如果 key 指定的哈希集不存在,会创建一个新的哈希集并与 key 关联。如果字段在哈希集中存在,它将被重写。
Remove(string hashId, string key)方法:对应于redis操作的hdel。从 key 指定的哈希集中移除指定的域。在哈希集中不存在的域将被忽略。如果 key 指定的哈希集不存在,它将被认为是一个空的哈希集,该命令将返回false。
Remove(string key)方法:对应于redis操作的del。直接删除key。
Get<T>方法:对应于redis操作的hget。返回该字段所关联的值。
GetAll<T>方法:对应于redis操作的hvals。获取哈希集中的值的列表,当 key 指定的哈希集不存在时返回空列表。
SetExpire方法:对应于redis操作的expire。设置缓存过期。
总结
redis操作很多很多,其实说是封装,也只是封装其中的一些常用操作。有兴趣的朋友可以用反编译工具去看下源码,就可以知道所有操作对应于redis
操作命令了。其实我个人觉得,使用C#操作redis只是语言需要,我们还是要学习它的客户端操作的。开发中,很多时候调试很慢的,我们可以直接通过
redis客户端操作去找,这样效率会更高一点。而且当操作命令熟练的时候,你会发现,客户端操作比调试操作快很多很多。所以,建议大家多多使用客户端操
作。刚开始会感觉很多需要记,熟能生巧,多操作,自然会很好。
在redis学习过程中,希望大神们能不吝赐教。同时也希望和我一样,在研究路上的同仁,有好的见解或是资料能跟小弟分享下,大家一起探讨学习下。我的QQ联系方式:296319075 随时联系,备注注明园友就好。大家秉承共同探讨、共同进步!如有转载,请注明出处,谢谢!^_^
还有,如果大家想要源代码的,可以说下,我会把自己用的放到网盘中或者通过QQ等其他方式发给需要的你。
C#中使用Redis学习二 在.NET4.5中使用redis hash操作的更多相关文章
- 【转】C#中使用Redis学习二 在.NET4.5中使用redis hash操作
摘要 上一篇讲述了安装redis客户端和服务器端,也大体地介绍了一下redis.本篇着重讲解.NET4.0 和 .NET4.5中如何使用redis和C# redis操作哈希表.并且会将封装的一些代码贴 ...
- Redis 学习(二) —— 数据类型及操作
Redis支持string.list.set.zset.hash等数据类型,这一篇学习redis的数据类型.命令及某些使用场景. 一.String,字符串 字符串是 Redis 最基本的数据类型.一个 ...
- Redis学习二:Redis高并发之主从模式
申明 本文章首发自本人公众号:壹枝花算不算浪漫,如若转载请标明来源! 感兴趣的小伙伴可关注个人公众号:壹枝花算不算浪漫 22.jpg 前言 前面已经学习了Redis的持久化方式,接下来开始学习Redi ...
- Redis学习二(数据操作).
key 操作 删除 key:del key 批量删除key:redis-cli -a(密码)keys "QXJ_*"| xargs redis-cli -a(密码)del 查看所有 ...
- php+redis 学习 二 悲观锁
<?php header('content-type:text/html;chaeset=utf-8'); /** * redis实战 * * 实现悲观锁机制 * */ $timeout = 5 ...
- Redis学习系列六ZSet(有序列表)及Redis数据结构的过期
一.简介 ZSet可以说是Redis中最有趣的数据结构了,因为他兼具了Hash集合和Set的双重特性,也是用的最多的,保证了value值的唯一性的同时,,同时又保证了高性能,最主要的是还可以给每个Va ...
- Redis学习之路(四)之Redis集群
[toc] #Redis集群 1.Redis Cluster简介 Redis Cluster为Redis官方提供的一种分布式集群解决方案.它支持在线节点增加和减少. 集群中的节点角色可能是主,也可能是 ...
- Redis学习之路(三)之Redis主从和哨兵模式
目录 一.Redis主从配置 1.环境说明 2.修改主从的redis配置文件 3.启动主从redis 3.数据同步验证 二.Redis哨兵模式 1.Redis sentinel介绍 2.Redis S ...
- Redis学习(一):CentOS下redis安装和部署
1.基础知识 redis是用C语言开发的一个开源的高性能键值对(key-value)数据库.它通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止redis支持的键值数据类型如下字符串.列表 ...
随机推荐
- 关于服务器raid的一个记录
今天下午,在装操作系统的时候,特意的测试了下raid1的性能. 1. 开启操作系统 直接正常开启操作系统,操作系统的硬盘做的是raid1,从而数据写俩份,从而在损坏一张盘之后,另外一张盘并不会收到影响 ...
- nginx实现多个域名共享80端口
server { listen 80; server_name server8085.duchong.cn; location / { proxy_pass http://127.0.0.1:8085 ...
- java多线程-慎重使用volatile关键字
Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量.这两种机制的提出都是为了实现代码线程的安全性.其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而 ...
- 前端开发之CSS篇三
主要内容: 一.CSS布局之浮动 二.清除浮动带来的问题 三.margin塌陷问题和水平居中 四.善用父级的的padding取代子级的margin 五.文本属性和字体 ...
- go_常量与枚举
package main import ( "fmt" "math" ) //常量的数值可以作为各种类型使用 func consts(){ const file ...
- SQL Pretty Printer不错的sql格式化工具
之前使用过sql server 2000的查询设计器和Toad for oracle 都有格式化Sql语句的功能,感觉很方便,尤其对于我这种有着轻微强迫症的人来说.当最近把SQL Server Man ...
- orcle clob字段查询
select utl_raw.cast_to_varchar2(DBMS_LOB.SUBSTR(column,2000,1)) from t
- myeclipse10.X以上的破解方法
破解补丁下载地址:http://pan.baidu.com/s/1dDzVP3z 本文使用的破解补丁对MyEclipse Standard/ Professional/ Blue/ Spring的10 ...
- code1044 导弹拦截
分析: 这套系统最多能拦截的导弹数 就是 导弹高度的最长不上升子序列(下降或相等) 如果要拦截所有导弹最少要配备多少套这种导弹拦截系统 就是 导弹高度的最长上升子序列 因此直接用dp求就可以了 a[i ...
- C# WebService中任务处理线程创建子线程后
protected void WriteLog(string message) { lock (lockObject) { var file = System.IO.File.AppendText(& ...