redis是否代替session

什么是redis

redis是一個(gè)開源的使用ANSI c語(yǔ)言編寫、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫(kù),并提供多種語(yǔ)言的API.

redis是否代替session

1.與其他用戶狀態(tài)保存方案比較

一般開發(fā)中用戶狀態(tài)使用Session或者Cookie,兩種方式各種利弊。

Session:在InProc模式下容易丟失,并且引起并發(fā)問(wèn)題。如果使用sqlserver或者SQLServer模式又消耗了性能

Cookie則容易將一些用戶信息暴露,加解密同樣也消耗了性能。

Redis采用這樣的方案解決了幾個(gè)問(wèn)題,

1.Redis存取速度快。

2.用戶數(shù)據(jù)不容易丟失。

3.用戶多的情況下容易支持集群。

4.能夠查看在線用戶。

5.能夠?qū)崿F(xiàn)用戶一處登錄。

6.支持持久化。

2.實(shí)現(xiàn)思路

1.我們知道session其實(shí)是在cookie中保存了一個(gè)sessionid,用戶每次訪問(wèn)都將sessionid發(fā)給服務(wù)器,服務(wù)器通過(guò)ID查找用戶對(duì)應(yīng)的狀態(tài)數(shù)據(jù)。

在這里我的處理方式也是在cookie中定義一個(gè)sessionid,程序需要取得用戶狀態(tài)時(shí)將sessionid做為key在Redis中查找。

2.同時(shí)session支持用戶在一定時(shí)間不訪問(wèn)將session回收。

借用Redis中Keys支持過(guò)期時(shí)間的特性支持這個(gè)功能,但是在續(xù)期方面需要程序自行攔截請(qǐng)求調(diào)用這個(gè)方法(demo有例子)

下面開始代碼說(shuō)明

3.Redis調(diào)用接口

首先引用ServiceStack相關(guān)DLL。

在web.config添加配置,這個(gè)配置用來(lái)設(shè)置Redis調(diào)用地址每臺(tái)服務(wù)用【,】隔開。主機(jī)寫在第一位

?<appsettings> ?????<!--每臺(tái)Redis之間用,分割.第一個(gè)必須為主機(jī)--> ????<add></add> ?</appsettings>

初始化配置

static?Managers() ????????{ ????????????string?sessionRedis=?ConfigurationManager.AppSettings["SessionRedis"]; ????????????string?timeOut?=?ConfigurationManager.AppSettings["SessionRedisTimeOut"]; ????????????if?(string.IsNullOrEmpty(sessionRedis)) ????????????{ ????????????????throw?new?Exception("web.config?缺少配置SessionRedis,每臺(tái)Redis之間用,分割.第一個(gè)必須為主機(jī)"); ????????????} ????????????if?(string.IsNullOrEmpty(timeOut)==false) ????????????{ ????????????????TimeOut?=?Convert.ToInt32(timeOut); ????????????} ????????????var?host?=?sessionRedis.Split(char.Parse(",")); ????????????var?writeHost?=?new?string[]?{?host[0]?}; ????????????var?readHosts?=?host.Skip(1).ToArray(); ????????????ClientManagers?=?new?PooledRedisClientManager(writeHost,?readHosts,?new?RedisClientManagerConfig ????????????{ ????????????????MaxWritePoolSize?=?writeReadCount,//“寫”鏈接池鏈接數(shù) ????????????????MaxReadPoolSize?=?writeReadCount,//“讀”鏈接池鏈接數(shù) ????????????????AutoStart?=?true ????????????}); ????????}

為了控制方便寫了一個(gè)委托

?///?<summary> ????????///?寫入 ????????///?</summary> ????????///?<typeparam></typeparam> ????????///?<param> ????????///?<returns></returns> ????????public?F?TryRedisWrite<f>(Func<iredisclient>?doWrite) ????????{ ????????????PooledRedisClientManager?prcm?=?new?Managers().GetClientManagers(); ????????????IRedisClient?client?=?null; ????????????try ????????????{ ????????????????using?(client?=?prcm.GetClient()) ????????????????{ ????????????????????return?doWrite(client); ????????????????} ????????????} ????????????catch?(RedisException) ????????????{ ????????????????throw?new?Exception("Redis寫入異常.Host:"?+?client.Host?+?",Port:"?+?client.Port); ????????????} ????????????finally ????????????{ ????????????????if?(client?!=?null) ????????????????{ ????????????????????client.Dispose(); ????????????????} ????????????} ????????}</iredisclient></f>

?一個(gè)調(diào)用的例子其他的具體看源碼

????????///?<summary> ????????///?以Key/Value的形式存儲(chǔ)對(duì)象到緩存中 ????????///?</summary> ????????///?<typeparam>對(duì)象類別</typeparam> ????????///?<param>要寫入的集合 ????????public?void?KSet(Dictionary<string>?value) ????????{ ????????????Func<iredisclient>?fun?=?(IRedisClient?client)?=&gt; ????????????{ ????????????????client.SetAll<t>(value); ????????????????return?true; ????????????}; ????????????TryRedisWrite(fun); ????????}</t></iredisclient></string>

4.實(shí)現(xiàn)Session

按上面說(shuō)的給cookie寫一個(gè)sessionid

?

????///?<summary> ????///?用戶狀態(tài)管理 ????///?</summary> ????public?class?Session ????{ ????????///?<summary> ????????///?初始化 ????????///?</summary> ????????///?<param> ????????public?Session(HttpContextBase?_context) ????????{ ????????????var?context?=?_context; ????????????var?cookie?=?context.Request.Cookies.Get(SessionName); ????????????if?(cookie?==?null?||?string.IsNullOrEmpty(cookie.Value)) ????????????{ ????????????????SessionId?=?NewGuid(); ????????????????context.Response.Cookies.Add(new?HttpCookie(SessionName,?SessionId)); ????????????????context.Request.Cookies.Add(new?HttpCookie(SessionName,?SessionId)); ????????????} ????????????else ????????????{ ????????????????SessionId?=?cookie.Value; ????????????} ????????} ????}

去存取用戶的方法

????????///?<summary> ????????///?獲取當(dāng)前用戶信息 ????????///?</summary> ????????///?<typeparam></typeparam> ????????///?<returns></returns> ????????public?object?Get<t>()?where?T:class,new() ????????{ ????????????return?new?RedisClient<t>().KGet(SessionId); ????????} ????????///?<summary> ????????///?用戶是否在線 ????????///?</summary> ????????///?<returns></returns> ????????public?bool?IsLogin() ????????{ ????????????return?new?RedisClient<object>().KIsExist(SessionId); ????????} ????????///?<summary> ????????///?登錄 ????????///?</summary> ????????///?<typeparam></typeparam> ????????///?<param> ????????public?void?Login<t>(T?obj)?where?T?:?class,new() ????????{ ????????????new?RedisClient<t>().KSet(SessionId,?obj,?new?TimeSpan(0,?Managers.TimeOut,?0)); ????????}</t></t></object></t></t>

?

?

6.續(xù)期

默認(rèn)用戶沒訪問(wèn)超過(guò)30分鐘注銷用戶的登錄狀態(tài),所以用戶每次訪問(wèn)都要將用戶的注銷時(shí)間推遲30分鐘

這需要調(diào)用Redis的續(xù)期方法

?

??????///?<summary> ????????///?延期 ????????///?</summary> ????????///?<param> ????????///?<param> ????????public?void?KSetEntryIn(string?key,?TimeSpan?expiresTime) ????????{ ????????????Func<iredisclient>?fun?=?(IRedisClient?client)?=&gt; ????????????{ ????????????????client.ExpireEntryIn(key,?expiresTime); ????????????????return?false; ????????????}; ????????????TryRedisWrite(fun); ????????}</iredisclient>

?

封裝以后

///?<summary> ///?續(xù)期 ///?</summary> public?void?Postpone() { new?RedisClient<object>().KSetEntryIn(SessionId,?new?TimeSpan(0,?Managers.TimeOut,?0)); }</object>

?

?

這里我利用了MVC3中的ActionFilter,攔截用戶的所有請(qǐng)求

namespace?Test { ????public?class?SessionFilterAttribute?:?ActionFilterAttribute ????{ ????????///?<summary> ????????///?每次請(qǐng)求都續(xù)期 ????????///?</summary> ????????///?<param> ????????public?override?void?OnActionExecuting(ActionExecutingContext?filterContext) ????????{ ????????????new?Session(filterContext.HttpContext).Postpone(); ????????} ????} }

?

在Global.asax中要注冊(cè)一下

public?static?void?RegisterGlobalFilters(GlobalFilterCollection?filters) ????????{ ????????????filters.Add(new?SessionFilterAttribute()); ????????} ????????protected?void?Application_Start() ????????{ ????????????RegisterGlobalFilters(GlobalFilters.Filters); ????????}

?

5.調(diào)用方式

為了方便調(diào)用借用4.0中的新特性,把Controller添加一個(gè)擴(kuò)展屬性

public?static?class?ExtSessions {public?static?Session?SessionExt(this?Controller?controller) ????{ ????????return?new?Session(controller.HttpContext); ????} }

?

調(diào)用方法

????public?class?HomeController?:?Controller ????{ ????????public?ActionResult?Index() ????????{ ????????????this.SessionExt().IsLogin(); ????????????return?View(); ????????} ????}

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊15 分享