您的位置:首页 > 技术中心 > 数据库 >

redis是否代替session

时间:2022-02-25 11:50

什么是Redis

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API.

1.与其他用户状态保存方案比较

一般开发中用户状态使用session或者cookie,两种方式各种利弊。

Session:在InProc模式下容易丢失,并且引起并发问题。如果使用SQLServer或者SQLServer模式又消耗了性能

Cookie则容易将一些用户信息暴露,加解密同样也消耗了性能。

Redis采用这样的方案解决了几个问题,

1.Redis存取速度快。

2.用户数据不容易丢失。

3.用户多的情况下容易支持集群。

4.能够查看在线用户。

5.能够实现用户一处登录。

6.支持持久化。

2.实现思路

1.我们知道session其实是在cookie中保存了一个sessionid,用户每次访问都将sessionid发给服务器,服务器通过ID查找用户对应的状态数据。

在这里我的处理方式也是在cookie中定义一个sessionid,程序需要取得用户状态时将sessionid做为key在Redis中查找。

2.同时session支持用户在一定时间不访问将session回收。

借用Redis中Keys支持过期时间的特性支持这个功能,但是在续期方面需要程序自行拦截请求调用这个方法(demo有例子)

下面开始代码说明

3.Redis调用接口

首先引用ServiceStack相关DLL。

在web.config添加配置,这个配置用来设置Redis调用地址每台服务用【,】隔开。主机写在第一位

  1. <appSettings>
  2. <!--每台Redis之间用,分割.第一个必须为主机-->
  3. <add key="SessionRedis" value="127.0.0.1:6384,127.0.0.1:6384"/>
  4. </appSettings>

初始化配置

  1. static Managers()
  2. {
  3. string sessionRedis= ConfigurationManager.AppSettings["SessionRedis"];
  4. string timeOut = ConfigurationManager.AppSettings["SessionRedisTimeOut"];
  5. if (string.IsNullOrEmpty(sessionRedis))
  6. {
  7. throw new Exception("web.config 缺少配置SessionRedis,每台Redis之间用,分割.第一个必须为主机");
  8. }
  9. if (string.IsNullOrEmpty(timeOut)==false)
  10. {
  11. TimeOut = Convert.ToInt32(timeOut);
  12. }
  13. var host = sessionRedis.Split(char.Parse(","));
  14. var writeHost = new string[] { host[0] };
  15. var readHosts = host.Skip(1).ToArray();
  16. ClientManagers = new PooledRedisClientManager(writeHost, readHosts, new RedisClientManagerConfig
  17. {
  18. MaxWritePoolSize = writeReadCount,//“写”链接池链接数
  19. MaxReadPoolSize = writeReadCount,//“读”链接池链接数
  20. AutoStart = true
  21. });
  22. }

为了控制方便写了一个委托

  1. /// <summary>
  2. /// 写入
  3. /// </summary>
  4. /// <typeparam name="F"></typeparam>
  5. /// <param name="doWrite"></param>
  6. /// <returns></returns>
  7. public F TryRedisWrite<F>(Func<IRedisClient, F> doWrite)
  8. {
  9. PooledRedisClientManager prcm = new Managers().GetClientManagers();
  10. IRedisClient client = null;
  11. try
  12. {
  13. using (client = prcm.GetClient())
  14. {
  15. return doWrite(client);
  16. }
  17. }
  18. catch (RedisException)
  19. {
  20. throw new Exception("Redis写入异常.Host:" + client.Host + ",Port:" + client.Port);
  21. }
  22. finally
  23. {
  24. if (client != null)
  25. {
  26. client.Dispose();
  27. }
  28. }
  29. }

一个调用的例子其他的具体看源码

  1. /// <summary>
  2. /// 以Key/Value的形式存储对象到缓存中
  3. /// </summary>
  4. /// <typeparam name="T">对象类别</typeparam>
  5. /// <param name="value">要写入的集合</param>
  6. public void KSet(Dictionary<string, T> value)
  7. {
  8. Func<IRedisClient, bool> fun = (IRedisClient client) =>
  9. {
  10. client.SetAll<T>(value);
  11. return true;
  12. };
  13. TryRedisWrite(fun);
  14. }

4.实现Session

按上面说的给cookie写一个sessionid

  1. /// <summary>
  2. /// 用户状态管理
  3. /// </summary>
  4. public class Session
  5. {
  6. /// <summary>
  7. /// 初始化
  8. /// </summary>
  9. /// <param name="_context"></param>
  10. public Session(HttpContextBase _context)
  11. {
  12. var context = _context;
  13. var cookie = context.Request.Cookies.Get(SessionName);
  14. if (cookie == null || string.IsNullOrEmpty(cookie.Value))
  15. {
  16. SessionId = NewGuid();
  17. context.Response.Cookies.Add(new HttpCookie(SessionName, SessionId));
  18. context.Request.Cookies.Add(new HttpCookie(SessionName, SessionId));
  19. }
  20. else
  21. {
  22. SessionId = cookie.Value;
  23. }
  24. }
  25. }

去存取用户的方法

  1. /// <summary>
  2. /// 获取当前用户信息
  3. /// </summary>
  4. /// <typeparam name="T"></typeparam>
  5. /// <returns></returns>
  6. public object Get<T>() where T:class,new()
  7. {
  8. return new RedisClient<T>().KGet(SessionId);
  9. }
  10. /// <summary>
  11. /// 用户是否在线
  12. /// </summary>
  13. /// <returns></returns>
  14. public bool IsLogin()
  15. {
  16. return new RedisClient<object>().KIsExist(SessionId);
  17. }
  18. /// <summary>
  19. /// 登录
  20. /// </summary>
  21. /// <typeparam name="T"></typeparam>
  22. /// <param name="obj"></param>
  23. public void Login<T>(T obj) where T : class,new()
  24. {
  25. new RedisClient<T>().KSet(SessionId, obj, new TimeSpan(0, Managers.TimeOut, 0));
  26. }

6.续期

默认用户没访问超过30分钟注销用户的登录状态,所以用户每次访问都要将用户的注销时间推迟30分钟

这需要调用Redis的续期方法

  1. /// <summary>
  2. /// 延期
  3. /// </summary>
  4. /// <param name="key"></param>
  5. /// <param name="expiresTime"></param>
  6. public void KSetEntryIn(string key, TimeSpan expiresTime)
  7. {
  8. Func<IRedisClient, bool> fun = (IRedisClient client) =>
  9. {
  10. client.ExpireEntryIn(key, expiresTime);
  11. return false;
  12. };
  13. TryRedisWrite(fun);
  14. }

封装以后

  1. /// <summary>
  2. /// 续期
  3. /// </summary>
  4. public void Postpone()
  5. {
  6. new RedisClient<object>().KSetEntryIn(SessionId, new TimeSpan(0, Managers.TimeOut, 0));
  7. }

这里我利用了MVC3中的ActionFilter,拦截用户的所有请求

  1. namespace Test
  2. {
  3. public class SessionFilterAttribute : ActionFilterAttribute
  4. {
  5. /// <summary>
  6. /// 每次请求都续期
  7. /// </summary>
  8. /// <param name="filterContext"></param>
  9. public override void OnActionExecuting(ActionExecutingContext filterContext)
  10. {
  11. new Session(filterContext.HttpContext).Postpone();
  12. }
  13. }
  14. }

在Global.asax中要注册一下

  1. public static void RegisterGlobalFilters(GlobalFilterCollection filters)
  2. {
  3. filters.Add(new SessionFilterAttribute());
  4. }
  5. protected void Application_Start()
  6. {
  7. RegisterGlobalFilters(GlobalFilters.Filters);
  8. }

5.调用方式

为了方便调用借用4.0中的新特性,把Controller添加一个扩展属性

  1. public static class ExtSessions
  2. {public static Session SessionExt(this Controller controller)
  3. {
  4. return new Session(controller.HttpContext);
  5. }
  6. }

调用方法

  1. public class HomeController : Controller
  2. {
  3. public ActionResult Index()
  4. {
  5. this.SessionExt().IsLogin();
  6. return View();
  7. }
  8. }

以上就是redis是否代替session的详细内容,更多请关注gxlsystem.com其它相关文章!

热门排行

今日推荐

热门手游