侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

Redis缓存详解

Redis  /  管理员 发布于 5年前   376

下面来正式分享今天的文章吧:

。搭建Redis服务端,并用客户端连接

。封装缓存父类,定义Get,Set等常用方法

。定义RedisCache缓存类,执行Redis的Get,Set方法

。构造出缓存工厂调用方法

下面一步一个脚印的来分享:

。搭建Redis服务端,并用客户端连接

首先,咋们去这个地址下载安装文件https://github.com/dmajkic/redis/downloads,我这里的版本是:redis-2.4.5-win32-win64里面有32位和64位的执行文件,我这里服务器是64位的下面给出截图和用到部分程序的说明:

现在,咋们直接可以用鼠标双击redis-server.exe这个应用程序,这样就打开了redis服务窗体(您也可以下载一个windows服务承载器,把redis服务运行在windows的服务中,就不用担心每次关闭redis服务黑色窗体后无法访问redis了),运行起来是这样:

有红色框的信息就表示成功了,这里redis服务监听的端口默认是6379,要修改端口或者更多的配置信息请找到redis.conf配置文件,具体配置信息介绍可以来这里http://www.shouce.ren/api/view/a/6231

再来,打开客户端连接服务端,咋们退到64bit文件夹的目录中,鼠标移到64bit文件夹上并且安装Shift键,同时点击鼠标的右键,选中"在此处打开命令窗口"这样快速进入到了该文件夹的cmd命令窗口中(当然不同的操作系统不同,这里演示的是windows的操作;还有其他进入的方式这里不做介绍,因为个人感觉这是最快的);然后,在命令窗口中录入redis-cli.exe -h localhost -p 6379回车来访问服务端,效果图:

再来看下服务端窗体截图:

没错这样客户端就连接上服务端了,可以简单在客户端执行下set,get命令:

如果是客户端要访问远程的redis服务端,只需要把localhost换成可访问的ip就行了如果还需要密码等更多配置请去上面的那个地址链接;

 。封装缓存父类,定义Get,Set等常用方法

先来,上父类的代码:

public class BaseCache : IDisposable { protected string def_ip = string.Empty; protected int def_port = 0; protected string def_password = string.Empty; public BaseCache() { } public virtual void InitCache(string ip = "", int port = 0, string password = "") { } public virtual bool SetCache<T>(string key, T t, int timeOutMinute = 10) where T : class,new() {  return false; } public virtual T GetCache<T>(string key) where T : class,new() {  return default(T); } public virtual bool Remove(string key) {  return false; } public virtual bool FlushAll() {  return false; } public virtual bool Any(string key) {  return false; } public virtual void Dispose(bool isfalse) {  if (isfalse)  {  } } //手动释放 public void Dispose() {  this.Dispose(true);  //不自动释放  GC.SuppressFinalize(this); } }

 这里定义的方法没有太多的注释,更多的意思我想看方法名称就明白了,这个父类主要实现了IDisposable,实现的Dispose()中主要用来释放资源并且自定义了一个 public virtual void Dispose(bool isfalse)方法,这里面有一句是GC.SuppressFinalize(this);按照官网介绍的意思是阻塞自动释放资源,其他的没有什么了,继续看下面的

。定义RedisCache缓存类,执行Redis的Get,Set方法

首先,咋们分别定义类RedisCache,MemcachedCache(这里暂未实现对memcache缓存的操作),并且继承BaseCache,重写Set,Get方法如下代码:

/// <summary> /// Redis缓存 /// </summary> public class RedisCache : BaseCache { public RedisClient redis = null; public RedisCache() {  //这里去读取默认配置文件数据  def_ip = "172.0.0.1";  def_port = 6379;  def_password = ""; } #region Redis缓存 public override void InitCache(string ip = "", int port = 0, string password = "") {  if (redis == null)  {  ip = string.IsNullOrEmpty(ip) ? def_ip : ip;  port = port == 0 ? def_port : port;  password = string.IsNullOrEmpty(password) ? def_password : password;  redis = new RedisClient(ip, port, password);  } } public override bool SetCache<T>(string key, T t, int timeOutMinute = 10) {  var isfalse = false;  try  {  if (string.IsNullOrEmpty(key)) { return isfalse; }  InitCache();  isfalse = redis.Set<T>(key, t, TimeSpan.FromMinutes(timeOutMinute));  }  catch (Exception ex)  {  }  finally { this.Dispose(); }  return isfalse; } public override T GetCache<T>(string key) {  var t = default(T);  try  {  if (string.IsNullOrEmpty(key)) { return t; }  InitCache();  t = redis.Get<T>(key);  }  catch (Exception ex)  {  }  finally { this.Dispose(); }  return t; } public override bool Remove(string key) {  var isfalse = false;  try  {  if (string.IsNullOrEmpty(key)) { return isfalse; }  InitCache();  isfalse = redis.Remove(key);  }  catch (Exception ex)  {  }  finally { this.Dispose(); }  return isfalse; } public override void Dispose(bool isfalse) {  if (isfalse && redis != null)  {  redis.Dispose();  redis = null;  } } #endregion } /// <summary> /// Memcached缓存 /// </summary> public class MemcachedCache : BaseCache { }

这里,用到的RedisClient类是来自nuget包引用的,这里nuget包是:

然后,来看下重写的InitCache方法,这里面有一些ip,port(端口),password(密码)参数,这里直接写入在cs文件中没有从配置文件读取,大家可以扩展下;这些参数通过RedisClient构造函数传递给底层Socket访问需要的信息,下面简单展示下RedisClient几个的构造函数:

public RedisClient(); public RedisClient(RedisEndpoint config); public RedisClient(string host); public RedisClient(Uri uri); public RedisClient(string host, int port); public RedisClient(string host, int port, string password = null, long db = 0);

至于Get,Set方法最终都是使用RedisClient对象访问的,个人觉得需要注意的是Set方法里面的过期时间参数,目前还没有试验这种情况的效果:

?通过这几种方法设置过期时间后,快到过期时间的时候如果此时有使用这个缓存key那么过期时间是否会往后自动增加过期时间有效期,这里暂时没有试验(这里是由于前面项目中的.net core框架中的memecache缓存都有这种设置,想来redis应该也有吧)

这里,需要重写下public override void Dispose(bool isfalse)方法,因为调用完RedisClient后需要释放,我们通过Dispose统一来手动释放,而不是直接在调用的时候使用using()

。构造出缓存工厂调用方法

接下来,咋们需要定义一个缓存工厂,因为上面刚才定义了一个RedisCache和MemcachedCache明显这里会有多个不同缓存的方法调用,所用咋们来定义个工厂模式来调用对应的缓存;这里的工厂模式没有使用直接显示创建new RedisCache(),new MemcachedCache()对象的方法,而是使用了反射的原理,创建对应的缓存对象;

先来,定义个枚举,枚举里面的声明的名字要和咋们缓存类的名称相同,代码如下:

public enum CacheType { RedisCache, MemcachedCache }

再来,定义个工厂来CacheRepository(缓存工厂),并且定义方法Current如下代码:

public static BaseCache Current(CacheType cacheType = CacheType.RedisCache) { var nspace = typeof(BaseCache); var fullName = nspace.FullName; var nowspace = fullName.Substring(0, fullName.LastIndexOf('.') + 1); return Assembly.GetExecutingAssembly().CreateInstance(nowspace + cacheType.ToString(), true) as BaseCache; }

*:通过传递枚举参数,来确定反射CreateInstance()方法需要用到的typeName参数,从而来定义需要访问的那个缓存对象,这里要注意的是加上了一个命名空间nowspace,因为缓存类可能和工厂类不是同一个命名空间,但是通常会和缓存基类是同命名空间所以在方法最开始的时候截取获取了缓存类需要的命名空间(这里看自身项目来定吧);

*:Assembly.GetExecutingAssembly()这个是用来获取当前应用程序集的路径,这里就避免了咋们使用Assembly.Load()方法还需要传递程序集的路径地址了

好了满上上面要求后,咋们可以在测试页面调用代码如:CacheRepository.Current(CacheType.RedisCache).SetCache<MoFlightSearchResponse>(keyData, value);就如此简单,咋们使用redis-cli.exe客户端来看下缓存起来的数据:

怎么样,您们的是什么效果呢,下面给出整体代码

#region CacheRepository 缓存工厂(默认存储Session中) /// <summary> /// 缓存枚举 /// </summary> public enum CacheType { BaseCache, RedisCache, MemcachedCache } /// <summary> /// 缓存工厂(默认存储Session中) /// </summary> public class CacheRepository { /// <summary> /// 缓存工厂(默认存储Session中, CacheKey = "SeesionKey") /// </summary> /// <param name="cacheType">缓存类型</param> /// <returns></returns> public static BaseCache Current(CacheType cacheType = CacheType.RedisCache) { var nspace = typeof(BaseCache); var fullName = nspace.FullName; var nowspace = fullName.Substring(0, fullName.LastIndexOf('.') + 1); return Assembly.GetExecutingAssembly().CreateInstance(nowspace + cacheType.ToString(), true) as BaseCache; } } /// <summary> /// 缓存基类(默认存储Session中) /// </summary> public class BaseCache : IDisposable { protected string def_ip = string.Empty; protected int def_port = 0; protected string def_password = string.Empty; protected string CacheKey = "SeesionKey"; public BaseCache() { } /// <summary> /// 获取自定义SessionId值 /// </summary> /// <param name="key">key:使用唯一的登陆账号</param> /// <returns>hash值的SessionId</returns> public virtual string GetSessionId(string key) { return Md5Extend.GetSidMd5Hash(key); } public virtual void InitCache(bool isReadAndWriter = true, string ip = "", int port = 0, string password = "") { } public virtual bool SetCache<T>(string key, T t, int timeOutMinute = 10, bool isSerilize = false) where T : class,new() { var isfalse = false; try { key = key ?? CacheKey; if (t == null) { return isfalse; } var session_json = JsonConvert.SerializeObject(t); HttpContext.Current.Session.Timeout = timeOutMinute; HttpContext.Current.Session.Add(key, session_json); isfalse = true; } catch (Exception ex) { throw new Exception(ex.Message); } return isfalse; } public virtual T GetCache<T>(string key = null, bool isSerilize = false) where T : class,new() { var t = default(T); try { key = key ?? CacheKey; var session = HttpContext.Current.Session[key]; if (session == null) { return t; } t = JsonConvert.DeserializeObject<T>(session.ToString()); } catch (Exception ex) { throw new Exception(ex.Message); } return t; } public virtual bool Remove(string key = null) { var isfalse = false; try { key = key ?? CacheKey; HttpContext.Current.Session.Remove(key); isfalse = true; } catch (Exception ex) { throw new Exception(ex.Message); } return isfalse; } /// <summary> /// 增加缓存时间 /// </summary> /// <returns></returns> public virtual bool AddExpire(string key, int nTimeMinute = 10) { return true; } public virtual bool FlushAll() { return false; } public virtual bool Any(string key) { return false; } public virtual bool SetHashCache<T>(string hashId, string key, T t, int nTimeMinute = 10) where T : class,new() { return false; } public virtual List<string> GetHashKeys(string hashId) { return null; } public virtual List<string> GetHashValues(string hashId) { return null; } public virtual T GetHashValue<T>(string hashId, string key) where T : class,new() { var t = default(T); return t; } public virtual bool RemoveHashByKey(string hashId, string key) { return false; } public virtual void Dispose(bool isfalse) { if (isfalse) { } } //手动释放 public void Dispose() { this.Dispose(true); //不自动释放 GC.SuppressFinalize(this); } } /// <summary> /// Redis缓存 /// </summary> public class RedisCache : BaseCache { public IRedisClient redis = null; public RedisCache() { //这里去读取默认配置文件数据 def_ip = "127.0.0.1"; def_port = 6379; def_password = ""; } #region Redis缓存 public static object _lockCache = new object(); public override void InitCache(bool isReadAndWriter = true, string ip = "", int port = 0, string password = "") { if (redis == null) { ip = string.IsNullOrEmpty(ip) ? def_ip : ip; port = port == 0 ? def_port : port; password = string.IsNullOrEmpty(password) ? def_password : password; //单个redis服务 //redis = new RedisClient(ip, port, password); //集群服务 如果密码,格式如:pwd@ip:port var readAndWritePorts = new List<string> { "[email protected]:6379" }; var onlyReadPorts = new List<string> {  "[email protected]:6378",  "[email protected]:6377" }; var redisPool = new PooledRedisClientManager(  readAndWritePorts,  onlyReadPorts,  new RedisClientManagerConfig  {  AutoStart = true,  //最大读取链接  MaxReadPoolSize = 20,  //最大写入链接  MaxWritePoolSize = 10  }) {  //每个链接超时时间  ConnectTimeout = 20,  //连接池超时时间  PoolTimeout = 60 }; lock (_lockCache) {  redis = isReadAndWriter ? redisPool.GetClient() : redisPool.GetReadOnlyClient(); } } } public override bool AddExpire(string key, int nTimeMinute = 10) { var isfalse = false; try { if (string.IsNullOrEmpty(key)) { return isfalse; } InitCache(); //isfalse = redis.ExpireEntryIn(key, TimeSpan.FromMinutes(nTimeMinute)); isfalse = redis.ExpireEntryAt(key, DateTime.Now.AddMinutes(nTimeMinute)); } catch (Exception ex) { } finally { this.Dispose(); } return isfalse; } public override bool SetCache<T>(string key, T t, int timeOutMinute = 10, bool isSerilize = false) { var isfalse = false; try { if (string.IsNullOrEmpty(key)) { return isfalse; } InitCache(); if (isSerilize) {  var data = JsonConvert.SerializeObject(t);  var bb = System.Text.Encoding.UTF8.GetBytes(data);  isfalse = redis.Set<byte[]>(key, bb, TimeSpan.FromMinutes(timeOutMinute)); } else { isfalse = redis.Set<T>(key, t, TimeSpan.FromMinutes(timeOutMinute)); } } catch (Exception ex) { } finally { this.Dispose(); } return isfalse; } public override T GetCache<T>(string key, bool isSerilize = false) { var t = default(T); try { if (string.IsNullOrEmpty(key)) { return t; } InitCache(false); if (isSerilize) {  var bb = redis.Get<byte[]>(key);  if (bb.Length <= 0) { return t; }  var data = System.Text.Encoding.UTF8.GetString(bb);  t = JsonConvert.DeserializeObject<T>(data); } else { t = redis.Get<T>(key); } } catch (Exception ex) { } finally { this.Dispose(); } return t; } public override bool Remove(string key) { var isfalse = false; try { if (string.IsNullOrEmpty(key)) { return isfalse; } InitCache(); isfalse = redis.Remove(key); } catch (Exception ex) { } finally { this.Dispose(); } return isfalse; } public override bool SetHashCache<T>(string hashId, string key, T t, int nTimeMinute = 10) { var isfalse = false; try { if (string.IsNullOrEmpty(hashId) || string.IsNullOrEmpty(key) || t == null) { return isfalse; } InitCache(); var result = JsonConvert.SerializeObject(t); if (string.IsNullOrEmpty(result)) { return isfalse; } isfalse = redis.SetEntryInHash(hashId, key, result); if (isfalse) { AddExpire(key, nTimeMinute); } } catch (Exception ex) { } finally { this.Dispose(); } return isfalse; } public override List<string> GetHashKeys(string hashId) { var hashKeys = new List<string>(); try { if (string.IsNullOrEmpty(hashId)) { return hashKeys; } InitCache(); hashKeys = redis.GetHashKeys(hashId); } catch (Exception ex) { } finally { this.Dispose(); } return hashKeys; } public override List<string> GetHashValues(string hashId) { var hashValues = new List<string>(); try { if (string.IsNullOrEmpty(hashId)) { return hashValues; } InitCache(); hashValues = redis.GetHashValues(hashId); } catch (Exception ex) { } finally { this.Dispose(); } return hashValues; } public override T GetHashValue<T>(string hashId, string key) { var t = default(T); try { if (string.IsNullOrEmpty(hashId) || string.IsNullOrEmpty(key)) { return t; } InitCache(); var result = redis.GetValueFromHash(hashId, key); if (string.IsNullOrEmpty(result)) { return t; } t = JsonConvert.DeserializeObject<T>(result); } catch (Exception ex) { } finally { this.Dispose(); } return t; } public override bool RemoveHashByKey(string hashId, string key) { var isfalse = false; try { if (string.IsNullOrEmpty(hashId) || string.IsNullOrEmpty(key)) { return isfalse; } InitCache(); isfalse = redis.RemoveEntryFromHash(hashId, key); } catch (Exception ex) { } finally { this.Dispose(); } return isfalse; } public override void Dispose(bool isfalse) { if (isfalse && redis != null) { redis.Dispose(); redis = null; } } #endregion } /// <summary> /// Memcached缓存 /// </summary> public class MemcachedCache : BaseCache { } #endregion

 这次分享的Redis缓存从搭建到使用希望给您们有帮助,还请多多支持点赞,谢谢。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!


  • 上一条:
    asp.net性能优化之使用Redis缓存(入门)
    下一条:
    RedisRepository 分享和纠错
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在Redis中能实现的功能、常见应用介绍(0个评论)
    • 2024年Redis面试题之一(0个评论)
    • 在redis缓存常见出错及解决方案(0个评论)
    • 在redis中三种特殊数据类型:地理位置、基数(cardinality)估计、位图(Bitmap)使用场景介绍浅析(2个评论)
    • Redis 删除 key用 del 和 unlink 有啥区别?(1个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2017-12
    • 2020-03
    • 2020-05
    • 2021-04
    • 2022-03
    • 2022-05
    • 2022-08
    • 2023-02
    • 2023-04
    • 2023-07
    • 2024-01
    • 2024-02
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客