.net core 中 Redis 入门
1.Redis基础
1.Redis是REmote DIctionary Servey(远程字典服务的缩写),他是以字典结构储存数据。Redis数据库中的键值除了可以是字符串,还可以还是:字符串,hash,list。set 。zset 类型
2.使用命令行操作
- 对string类型 设置值set k1 v1
- 对string 类型 获取值 get k1
- 对string 类型 设置多个set ,获取多个get。。即
mset k1 v1 k2 v2 k3 v3
mget k1 k2 k3 - 对 hash 类型进行设置
hset h1 name li - 对于hash 值也可以同时设置多个值
hmset h1 name li age 18
hgetall 获取所有的值 - 对于List类型
lpush L1 v1 :在左边给L1数组添加v1
lrange L1 0 -1 : 借鉴了Python的用法 -1表示最后一个 - 对于set 类型
sadd S1 V1 : 添加值
smembers S1 : 获取值
订阅者发布者模式:
直接结果如下图(很简单):
发布者只要一发布消息,所有的订阅者都能收到;
Redis 在.net core 中的使用
1.redis文件夹中相关文件的使用
引用第三方包:
2.使用 Redis 中的 string 命令:
using (RedisClient client=new RedisClient("127.0.0.1",6379))
{
//删除所有的key,默认删除的是DB0
client.FlushDb();
//删除所有数据库中的key
//Flush 冲洗所有
client.FlushAll();
client.Set<string>("名字", "朝夕教育",TimeSpan.FromSeconds(1));//过期时间一分钟.
Console.WriteLine("正确的输出如下:");
Console.WriteLine(client.Get<string>("名字"));
#region 设置多个key
//批量的读写:
client.SetAll(new Dictionary<string, string>
{
{ "id","001"},
{"name","zhao" }
});
var getall =
client.GetAll<string>(new string[] { "id", "name", "number" });
foreach (var item in getall)
{
Console.WriteLine(item);
}
#endregion
}
3.用 Redis 实现秒杀的小例子
秒杀中存在的困境:要在数据库中获取出售的商品数量。容易超卖
解决方案:
- 给数据库加锁,相当于把多线程工作改成单线程了
- Redis 本身就是单线程服务
注意:
- 多线程一定比单行程快?(错)
- redis 是一个分布式的数据库,数据在多个客户端上共享。
用redis实现秒杀的小例子
public static void Show(string id, int minute)
{
Console.WriteLine($"在{minute}分0秒正式开始秒杀");
bool 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");
//var num1 = client.Incr("number"); 这个是自增操作;
if (num<0)
{
Console.WriteLine(name+"**********抢购失败");
}
else
{
Console.WriteLine(name+"************抢购成功");
}
}
});
Thread.Sleep(10);
}} } }
Redis的使用场景
- 秒杀场景
- Redis计数器。。当有人恶意访问时,控制一分钟只能处理1000个请求,
- 因为关系型数据库是放在磁盘里面的,读取速度过慢,所以可以先用redis记录,然后每隔5分钟,往数据库里面记录一次。
- set 类型的数据,可以应用于微博点赞
用string做缓存的都是菜鸟。现在都用 hash
1.hash的键值只能是字符串:
要想批量读取或者写入 hash ,要先建立一个 字典
使用hash记录数据,具体代码如下:
using (RedisClient client = new RedisClient("127.0.0.1", 6379))
{
client.FlushDb();
client.FlushAll();
string people = "zhao de peng";
client.SetEntryInHash(people,"id","001");
Console.WriteLine("下边是进来以后的打印结果");
Console.WriteLine(client.GetValuesFromHash(people,"id").FirstOrDefault());
client.SetEntryInHash(people,"age","20");
Console.WriteLine(client.GetValuesFromHash(people,"age").FirstOrDefault());
client.SetEntryInHash(people,"score","100");
Console.WriteLine(client.GetValuesFromHash(people,"score").FirstOrDefault());
Console.WriteLine("@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
#region 批量新增 Key 值
string www = "zhao_peng";
Dictionary<string, string> pairs = new Dictionary<string, string>();
pairs.Add("id01","008");
pairs.Add("name01", "zhao");
client.SetRangeInHash(www,pairs);
//如果要带s的话就加上这句话
Console.WriteLine(client.GetValuesFromHash(www,"id01").FirstOrDefault());
Console.WriteLine(client.GetValueFromHash(www,"name01"));
var list = client.GetValuesFromHash(www, "id01", "name01");
Console.WriteLine("****************");
foreach (var item in list)
{
Console.WriteLine(item);
}
#endregion
}
使用hash后的结果:
Set 类型的数据
可用于防止微博或者朋友圈重复点赞,
set设置以后是这样的
交集和并集 关于 set 具体代码如下:
public static void Show()
{
#region Set 不重复的集合
using (RedisClient client = new RedisClient("127.0.0.1", 6379))
{
client.FlushDb();
client.FlushAll();
string key = "set_name";
var litaibai = new UserInfo() { Id = 1, Name = "李白" };
client.AddItemToSet(key, JsonConvert.SerializeObject(litaibai));
Console.WriteLine("已经写成功了");
Console.WriteLine("set 开始了");
client.AddRangeToSet
(key, new List<string>() { "001", "001", "002", "003", "004", "005", "005", "006" });
Console.WriteLine(client.GetSetCount(key));
}
#endregion
#region 并集
using (RedisClient client = new RedisClient("127.0.0.1", 6379))
{
client.FlushDb();
client.FlushAll();
string keyone = "keyOne";
string keyTwo = "keyTwo";
client.AddRangeToSet(keyone, new List<string>() { "001", "002", "003", "004" });
client.AddRangeToSet(keyTwo, new List<string>() { "001", "002", "003", "005" });
var unionlist = client.GetUnionFromSets("keyOne", "keyTwo");
Console.WriteLine("返回并集结果");
foreach (var item in unionlist)
{
Console.WriteLine(item);
}
Console.WriteLine(client.GetSetCount(keyone));
}
#endregion
#region 交集
using (RedisClient client = new RedisClient("127.0.0.1", 6379))
{
client.FlushDb();
client.FlushAll();
string keyone = "keyOne";
string keyTwo = "keyTwo";
client.AddRangeToSet
(keyone, new List<string>() { "001", "002", "003", "004" });
client.AddRangeToSet
(keyTwo, new List<string>() { "001", "002", "003", "005" });
//核心就是下边这一句
var unionlist = client.GetIntersectFromSets("keyOne", "keyTwo");
Console.WriteLine("返回并集结果");
foreach (var item in unionlist)
{
Console.WriteLine(item);
}
Console.WriteLine(client.GetSetCount(unionlist.ToString()));
}
#endregion }
}
Zset 设置的时候会有个分数,最后会根据分数进行排序
#region Zset
using (RedisClient client = new RedisClient("127.0.0.1", 6379))
{
client.FlushDb();
client.FlushAll();
string Zset_key = "keyOne";
//Zset 会有个默认的分数,最后会根据分数来排序
client.AddItemToSortedSet(Zset_key,"ccc",33);
Console.WriteLine("ok");
}
#endregion
List 的使用
list也是只有值(只有string是一行,其他的都是表)
list可以根据其特性,实现秒杀的功能(分布式缓存,就算是后台挂了也没事)
(1)Client 端的使用
public static void Show(string id, int minute)
{
Console.WriteLine($"在{minute}分0秒进行秒杀");
var flag = true;
while (flag)
{
// if (DateTime.Now.Minute == minute)
Console.WriteLine(DateTime.Now.Minute);
if (DateTime.Now.Minute==minute)
{
flag = false;
for (int i = 0; i < 100; i++)
{
string name = $"id为{id}客户端的第{i}次抢购";
Console.WriteLine(name);
Task.Run(() =>
{
using (RedisClient client = new RedisClient("127.0.0.1", 6379))
{
OrderInfo orderInfo = new OrderInfo()
{
ID = name,
OrderTime = DateTime.Now.ToString("yyyy-mm-dd-hh:mm:ss:fff")
};
string YonghuList = "User";
//加到队列里面;
client.AddItemToList(YonghuList, JsonConvert.SerializeObject(orderInfo));
Console.WriteLine($"{name}恭喜你,已经下单成功了");
}
} );
Thread.Sleep(1000);
}} } }
2.Server端:
using (RedisClient client = new RedisClient("127.0.0.1", 6379))
{
OrderInfo orderInfo = new OrderInfo();
while (true)
{
string YonghuList = "User";
//是移除,start 注意
var listvalue = client.RemoveStartFromList(YonghuList);
if (!string.IsNullOrWhiteSpace(listvalue))
{
//串行化是指:把对象存储到介质中(比如文件),以二进制的方式通过网络传输;
//反串行化指:从这些连续的数据中重构一个与原始对象相同的对象;
var order = JsonConvert.DeserializeObject<OrderInfo>(listvalue);
//下班 就可以做业务处理了。
Console.WriteLine("已经处理完的单子" + listvalue);
//Console.WriteLine($"消费完成:{order.ID}消费的时间{order.OrderTime}");
}
else
{
break;
}
Thread.Sleep(1000);
}
}
题外话
- using 的用法: 在某个代码片段中使用了类的实例,但是希望无论何时什么原因,只要离开了代码段。这个类的实例就会被 dispose 掉
using(建立一个新类)
{
对类做点东西
}
-
JsonConvert.SerialixeObject () 是序列化成Json格式,但是本质依然是字符串格式:
-
3.字典类型:字典名字就是个 table 的表明: 里面存放的还是键值对,想要取出来,无论往里放什么东西,都是键值对的格式,用JsonConvert.SerialixeObject()也一样,就要用 foreach 循环。
-
Hash 的话有 key - value 的键值对,如果没有的话,只有一个value。用redis Desktop Manager工具看到的最前边的序号,是自动生成的。什么用处我还不清楚;
-
匿名类的话,是 new 后边直接加 { }; 后边带()的这种 new class () ,是在声明类的同时给他赋值.。
参考文献
https://www.bilibili.com/video/BV1kg4y1i7mN/