安装Nuget包:ServiceStack.Redis
连接数据库
| using (RedisClient client = new RedisClient("127.0.0.1", 6379)) |
| { |
| |
| client.FlushDb(); |
| |
| client.FlushAll(); |
| |
| ...... |
| } |
使用String
设置key-value
| client.Set<string>("name", "编程"); |
| Console.WriteLine("正确输出如下"); |
| Console.WriteLine(client.Get<string>("name")); |
| Console.WriteLine("第二种输出"); |
| Console.WriteLine(client.GetValue("name")); |
| Console.WriteLine(JsonConvert.DeserializeObject<string>(client.GetValue("name"))); |
设置多个key的value
| |
| client.SetAll(new Dictionary<string, string>{{"id","001" },{"name","路飞" },}); |
| |
| var getall = client.GetAll<string>(new string[]{ "id","name","number", }); |
| foreach (var item in getall) |
| { |
| Console.WriteLine(item); |
| } |
| |
| |
| |
设置key的value并设置过期时间
| #region 设置key的value并设置过期时间 |
| client.Set<string>("name", "路飞", TimeSpan.FromSeconds(1)); |
| Task.Delay(1 * 1000).Wait(); |
| Console.WriteLine(client.Get<string>("name")); |
| #endregion |
| |
| #region 设置key的value并设置过期时间 |
| client.Set<string>("name", "路飞", DateTime.Now.AddSeconds(1)); |
| |
| Console.WriteLine("刚写进去的结果"); |
| Console.WriteLine(client.Get<string>("name")); |
| Task.Delay(1 * 1000).Wait(); |
| Console.WriteLine("1秒钟之后的结果"); |
| Console.WriteLine(client.Get<string>("name")); |
| |
| client.Set<string>("class", "优秀班级", TimeSpan.FromSeconds(10)); |
| Task.Delay(1 * 1000).Wait(); |
| Console.WriteLine(client.Get<string>("class")); |
| #endregion |
更改value值
| #region 在原有key的value值之后追加value |
| client.AppendToValue("name", "I"); |
| client.AppendToValue("name", " "); |
| client.AppendToValue("name", "LOVE YOU"); |
| Console.WriteLine(client.Get<string>("name")); |
| #endregion |
| |
| #region 获取旧值赋上新值 |
| client.Set("name", "路飞"); |
| |
| var value = client.GetAndSetValue("name", "路飞"); |
| Console.WriteLine("原先的值" + value); |
| Console.WriteLine("新值" + client.GetValue("name")); |
| #endregion |
自增自减
| #region 自增1,返回自增后的值 |
| |
| Console.WriteLine(client.Incr("sid")); |
| Console.WriteLine(client.Incr("sid")); |
| Console.WriteLine(client.Incr("sid")); |
| Console.WriteLine("哈哈哈"); |
| Console.WriteLine(client.GetValue("sid")); |
| |
| client.IncrBy("sid", 2); |
| Console.WriteLine(client.Get<string>("sid")); |
| client.IncrBy("sid", 100); |
| Console.WriteLine("最后的结果***" + client.GetValue("sid")); |
| #endregion |
| |
| #region 自减1,返回自减后的值 |
| Console.WriteLine(client.Decr("sid")); |
| Console.WriteLine(client.Decr("sid")); |
| Console.WriteLine(client.Decr("sid")); |
| Console.WriteLine("最后的结果" + client.GetValue("sid")); |
| |
| client.DecrBy("sid", 2); |
| Console.WriteLine("最终的结果" + client.GetValue("sid")); |
| #endregion |
add 和set 的区别
| #region add 和set 的区别? |
| |
| |
| Console.WriteLine(client.Add("name", "路飞")); |
| Console.WriteLine(client.Add("name", "你很好路飞")); |
| Console.WriteLine(client.Get<string>("name")); |
| |
| |
| |
| Console.WriteLine(client.Set("name", "路飞")); |
| Console.WriteLine(client.Set("name", "你很好路飞")); |
| Console.WriteLine(client.Get<string>("name")); |
| #endregion |
模拟秒杀程序
假如有10个商品,先存入redis数据库
| |
| |
| |
| var builder = new ConfigurationBuilder().AddCommandLine(args); |
| var configuration = builder.Build(); |
| string id = configuration["id"]; |
| int minute = int.Parse(configuration["minute"]); |
| Console.WriteLine("开始" + id); |
| |
| using (RedisClient client = new RedisClient("127.0.0.1", 6379)) |
| { |
| |
| client.Set<int>("number", 10); |
| } |
| Seckill.Show(id, minute); |
秒杀方法,开启10个线程进行抢购,当数据库中商品数量为0时抢购失败。
| public class Seckill |
| { |
| public static void Show(string id,int minute) |
| { |
| |
| Console.WriteLine($"在{minute}分0秒正式开启秒杀!"); |
| var flag = true; |
| while (flag) |
| { |
| if(DateTime.Now.Minute == minute) |
| { |
| flag = false; |
| for (int i = 0; i < 10; i++) |
| { |
| string name = $"客户端{id}号:{i}"; |
| Task.Run(()=> |
| { |
| using (RedisClient client = new RedisClient("127.0.0.1", 6379)) |
| { |
| |
| var num = client.Decr("number"); |
| if (num < 0) |
| { |
| Console.WriteLine(name + "抢购失败!"); |
| } |
| else |
| { |
| Console.WriteLine(name + "恭喜,抢购成功!"); |
| } |
| } |
| }); |
| Thread.Sleep(10); |
| } |
| } |
| Thread.Sleep(10); |
| } |
| Console.ReadLine(); |
| } |
| } |
我们开启三个客户端,在42分钟时模拟用户开始秒杀。
| 客户端1 |
| F:\RedisC1\bin\Debug\netcoreapp3.1>dotnet RedisC1.dll --id=1 minute=42 |
| 开始1 |
| 在42分0秒正式开启秒杀! |
| 客户端1号:0恭喜,抢购成功! |
| 客户端1号:1恭喜,抢购成功! |
| 客户端1号:2恭喜,抢购成功! |
| 客户端1号:3恭喜,抢购成功! |
| 客户端1号:4抢购失败! |
| 客户端1号:5抢购失败! |
| 客户端1号:6抢购失败! |
| 客户端1号:7抢购失败! |
| 客户端1号:8抢购失败! |
| 客户端1号:9抢购失败! |
| |
| 客户端2 |
| F:\RedisC1\bin\Debug\netcoreapp3.1>dotnet RedisC1.dll --id=2 minute=42 |
| 开始2 |
| 在42分0秒正式开启秒杀! |
| 客户端2号:0恭喜,抢购成功! |
| 客户端2号:1恭喜,抢购成功! |
| 客户端2号:2恭喜,抢购成功! |
| 客户端2号:3抢购失败! |
| 客户端2号:4抢购失败! |
| 客户端2号:5抢购失败! |
| 客户端2号:6抢购失败! |
| 客户端2号:7抢购失败! |
| 客户端2号:8抢购失败! |
| 客户端2号:9抢购失败! |
| |
| F:\RedisC1\bin\Debug\netcoreapp3.1>dotnet RedisC1.dll --id=3 minute=42 |
| 开始3 |
| 在42分0秒正式开启秒杀! |
| 客户端3号:0恭喜,抢购成功! |
| 客户端3号:1恭喜,抢购成功! |
| 客户端3号:2恭喜,抢购成功! |
| 客户端3号:3抢购失败! |
| 客户端3号:4抢购失败! |
| 客户端3号:5抢购失败! |
| 客户端3号:6抢购失败! |
| 客户端3号:7抢购失败! |
| 客户端3号:8抢购失败! |
| 客户端3号:9抢购失败! |
从结果中可以看到10个商品被抢购成功,其余失败。
为什么redis可以解决高并发情况下的秒杀,而且在代码中没有看到任何的锁?
因为redis它是一个单线程的服务。
很多人都有个误区:
- 误区1:多线程(cpu上下文切换)一定比单线程快?。
- 误区2:redis是单线程服务,那么redis服务里面是不是只有一个线程。
其实单线程代表的是处理命令或者指令的时候,后台只有一个处理指令线程。
我们发送给redis服务的指令,在同一时刻只会执行一条指令。
redis 它是一个支持分布式的内存数据库,它有多种数据类型,为什么快?
因为是它内存数据库,关系型数据库是操作硬盘的(好比人记的笔记),而内存数据库操作是内存(好比人的大脑记忆)。
官网推荐优先使用hash
向hashid集合中添加key/value
| #region 向hashid集合中添加key/value |
| client.SetEntryInHash(hashid, "id", "001"); |
| Console.WriteLine(client.GetValuesFromHash(hashid, "id").FirstOrDefault()); |
| client.SetEntryInHash(hashid, "name", "路飞"); |
| Console.WriteLine(client.GetValuesFromHash(hashid, "name").FirstOrDefault()); |
| client.SetEntryInHash(hashid, "socre", "100"); |
| Console.WriteLine(client.GetValuesFromHash(hashid, "socre").FirstOrDefault()); |
| #endregion |
| |
| #region 如果hashid集合中存在key/value则不添加返回false,如果不存在在添加key/value,返回true |
| Console.WriteLine(client.SetEntryInHashIfNotExists(hashid, "name", "123")); |
| Console.WriteLine(client.SetEntryInHashIfNotExists(hashid, "name", "123 哈哈哈")); |
| Console.WriteLine(client.GetValuesFromHash(hashid, "name").FirstOrDefault()); |
| #endregion |
批量新增key的值
| #region 批量新增key的值 |
| Dictionary<string, string> pairs = new Dictionary<string, string>(); |
| pairs.Add("id", "001"); |
| pairs.Add("name", "路飞"); |
| client.SetRangeInHash(hashid, pairs); |
| |
| Console.WriteLine(client.GetValueFromHash(hashid, "id")); |
| Console.WriteLine(client.GetValueFromHash(hashid, "name")); |
| |
| var list = client.GetValuesFromHash(hashid, "id", "name", "abc"); |
| Console.WriteLine("*********"); |
| foreach (var item in list) |
| { |
| Console.WriteLine(item); |
| } |
| #endregion |
存储对象到hash集合中
| #region 存储对象T t到hash集合中 |
| |
| client.StoreAsHash<UserInfo>(new UserInfo() { Id = 2, Name = "路飞", number = 0 }); |
| |
| |
| client.StoreAsHash<UserInfo>(new UserInfo() { Id = 1, Name = "路飞2" }); |
| |
| |
| Console.WriteLine(client.GetFromHash<UserInfo>(1).Name); |
| var olduserinfo = client.GetFromHash<UserInfo>(1); |
| olduserinfo.number = 4; |
| client.StoreAsHash(olduserinfo); |
| Console.WriteLine("最后的结果" + client.GetFromHash<UserInfo>(1).number); |
| client.StoreAsHash(new UserInfoTwo() { Id = "001", Name = "路飞2" }); |
| Console.WriteLine(client.GetFromHash<UserInfoTwo>("001").Name); |
| client.StoreAsHash(new UserInfoTwo() { Id = "002", Name = "路飞" }); |
| Console.WriteLine(client.GetFromHash<UserInfoTwo>("002").Name); |
| |
| UserInfo lisi = new UserInfo() { Id = 1, Name = "李四", number = 0 }; |
| client.StoreAsHash(lisi); |
| Console.WriteLine(client.GetFromHash<UserInfo>(1).number); |
| |
| var oldzhang = client.GetFromHash<UserInfo>(1); |
| oldzhang.number++; |
| client.StoreAsHash(oldzhang); |
| #endregion |
其他方法
| |
| var dics = client.GetAllEntriesFromHash(hashid); |
| |
| |
| client.GetHashCount(hashid); |
| |
| |
| var keys = client.GetHashKeys(hashid); |
| |
| |
| var values = client.GetHashValues(hashid); |
| |
| |
| client.RemoveEntryFromHash(hashid, "id"); |
| |
| |
| client.HashContainsEntry(hashid, "id")); |
| |
| |
| |
| client.IncrementValueInHash(hashid, "number", 2)); |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了