.Net中初探Redis
一、简介
Redis是著名的NOSQL数据库,本质就是存储键值对结构的数据,为存储键值对数据做了优化,在大型网站中应用很多。Redis提供了数据的自动过期处理,因此适合存储临时数据。
和Redis类似的还有Memcached, Redis可以把数据持久化到硬盘中,而Memcached是放到内存中,重启后就消失,一般用Memcached做缓存。
二、Redis服务器的部署(Windows)
Redis服务器有Linux、Windows版,Linux版性能好适合生产环境。这里只说明Windows里配置Redis服务器,用于开发。
1.安装Redis服务
文件下载:redisbin_x32
安装路径不要包含中文或其他特殊符号,解压后服务相关文件如下:
redis-server.exe单击该文件虽然可以开启服务,但是要一直保证这个文件不能关闭,双击点开如图:
2.把Redis服务配置到Windows服务里
说明:配置此项后,不必去通过找到“redis-server.exe”文件单击打开一直挂着,才能使用服务。
文件下载:RedisWatcher1
解压安装后相关文件如下:
修改“watcher.conf”文件里,打开文件,进行图片说明的操作
修改后去Windows服务里开启Redis服务,如图:
三、在.net中操作Redis
1.在项目中导入相关的.dll文件的引用
文件下载:Redis.Net驱动
相关.dll如图:
2.创建一个RedisManage类
写入以下关键代码:
1 using ServiceStack.Redis; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Redis_Test 9 { 10 class RedisManage 11 { 12 13 public static PooledRedisClientManager ClientManager { get; private set; } 14 static RedisManage() 15 { 16 RedisClientManagerConfig redisConfig = new RedisClientManagerConfig(); 17 redisConfig.MaxWritePoolSize = 128; 18 redisConfig.MaxReadPoolSize = 128; 19 20 //可以读写分离,指定一台服务器读,一台写。 21 // new PooledRedisClientManage(读写的服务器地址,只读的服务器地址 22 ClientManager = new PooledRedisClientManager(new string[] { "127.0.0.1" }, 23 new string[] {"127.0.0.1"}, redisConfig); 24 } 25 26 27 } 28 }
3.存储信息的方法
1 2 using (IRedisClient con = RedisManage.ClientManager.GetClient()) 3 { 4 //存数据 5 con.Set<int>("age", 18); 6 Dictionary<string, string> dic = new Dictionary<string, string>(); 7 dic["yzk"] = "test"; 8 con.Set<Dictionary<string, string>>("dic", dic); 9 10 }
4.读取数据
1 using (IRedisClient con = RedisManage.ClientManager.GetClient()) 2 { 3 //取数据 4 int age = con.Get<int>("age"); 5 Console.WriteLine(age); 6 Dictionary<string, string> dic = con.Get<Dictionary<string, string>>("dic"); 7 Console.WriteLine(dic["yzk"]); 8 9 }
5. 支持写入数据设置超时:
bool Set<T>(string key, T value, DateTime expiresAt);
第三个参数DateTime,可以指定数据到期时间,到期数据将不存在服务器里
四、在项目解决的一些问题
1.同一个用户名只能在一台电脑或者一个浏览器中登陆,严格来说是一个Session,Web中很难区别是否是同一台电脑,
这里的本质是使用用户名与SessionID进行键值对关联,存储到Redis中。
技术思路:在编写用户登陆代码处,将用户名(唯一)做为键,当前的SessionId作为值,存储到Redis数据库中。然后在每次请求页面时,
就把当前SessionID取出,在把对应的Redis中的SessionId取出,两者进行比较,假如这时用户已经换了浏览器登陆,那么Redis中对应的SessionID将覆盖了,
两者不对等,那么就证明该用户在其他地方进行了登陆。
俗语:但凡登陆就要用当前SessionID覆盖Redis中的SessionID,只要每当请求,发现当前SessionID与Redis中的不同,该页面就要清除登陆,清除Session,说明这个用户去了其他位置登陆了。
代码参考,登录成功某处:
1 context.Session["user"] = model; 2 //用户名与SessionId键值对关系存储到Redis中 3 using (var con = RedisManage.ClientManager.GetClient()) 4 { 5 //存数据 6 con.Set<string>(model.username,context.Session.SessionID); 7 8 }
由于,用户每次请求页面都要检查,我将此操作配置到Global文件中:
参考代码:
1 using Common; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Web; 6 using System.Web.Security; 7 using System.Web.SessionState; 8 using Model; 9 namespace rupeng 10 { 11 public class Global : System.Web.HttpApplication 12 { 13 14 public override void Init() 15 { 16 base.Init(); 17 //必须到Init()中监听 18 //每个需要Seesion页面启动都会执行AcquireRequestState事件 19 //AcquireRequestState事件执行的时候Session已经准备好了 20 this.AcquireRequestState += Global_AcquireRequestState; 21 } 22 23 void Global_AcquireRequestState(object sender, EventArgs e) 24 { 25 if (HttpContext.Current.Session==null) 26 { 27 return; 28 } 29 30 31 if (Context.Session["user"]==null) //排除用户没有登录 32 { 33 return; 34 } 35 user_guest model= Context.Session["user"] as user_guest; 36 using (var con = RedisManage.ClientManager.GetClient()) 37 { 38 string redis_sId = con.Get<string>(model.username); 39 40 //发现不对等,用户在其他位置登陆了,销毁当前Seesion 41 if (redis_sId!=Context.Session.SessionID) 42 { 43 Context.Session.Clear(); 44 Context.Session.Abandon(); 45 } 46 47 } 48 49 50 } 51 52 53 protected void Application_Start(object sender, EventArgs e) 54 { 55 56 } 57 58 protected void Session_Start(object sender, EventArgs e) 59 { 60 61 } 62 63 protected void Application_BeginRequest(object sender, EventArgs e) 64 { 65 66 } 67 68 protected void Application_AuthenticateRequest(object sender, EventArgs e) 69 { 70 71 } 72 73 protected void Application_Error(object sender, EventArgs e) 74 { 75 76 } 77 78 protected void Session_End(object sender, EventArgs e) 79 { 80 81 } 82 83 protected void Application_End(object sender, EventArgs e) 84 { 85 86 } 87 } 88 }