Redis之品鉴之旅(一)
Redis之品鉴之旅(一)
好知识就如好酒,需要我们坐下来,静静的慢慢的去品鉴。Redis作为主流nosql数据库,在提升性能的方面是不可或缺的。下面就拿好小板凳,我们慢慢的来一一品鉴。
1)redis号称是大数据高并发的利器,那么到底什么是redis?
redis是nosql(not only sql,不仅仅是sql语句),它提供了各种操作的api,不像我们的关系型数据库使用sql语句来操作数据库。
redis全称Remote Dictionary Server(远程字典服务),首先是一个字典,其次是内存数据库(读写速度:CPU>内存>硬盘)。
redis方便扩展,关系型数据库在进行数据扩展时需要 一些列的操作(比如使用了ORM,需要再实体类中增加字段,然后修改dto,修改映射,最后做数据迁移),相对而言redis就会简化很多,只要是数据都可以直接存进去,不需要提前去规范字段。
2)redis8种数据结构:string,hash,list,set,zset,bitmaps,hyperlogloss,streams。前5种是最常用的,后面3中比较少用。
3)redis分布式存储,多台机器实现一个内存共享
4)redis是单线程,但不是redis服务只有一个线程。
单线程的原子性可以理解为不需要锁,不需要上下文切换。单线程就是一个任务一个人做,多线程可以理解成一个任务多个人做,肯定有一个指导这些人去合理做的人。如果需要多线程实现原子性,就会涉及到各种锁、上下文切换 。典型的单线程服务就是nginx,但是在大数据高并发下nginx为什么还是那么的快呢?这就是使用了IO多路复用,redis同样使用,原理一模一样。
后面如果有时间会单独对IO多路复用进行理解。
5)使用的redis客户端的库:ServiceStack.Redis。这个库对客户端的请求操作是有限制的,每小时6000次,但是可以通过修改源码的形式进行限制,不建议反编译dll。
下面我们看一下各种数据结果的API
1)string类型,先上代码
//IP地址,端口,密码,db序号(默认0)
using (RedisClient client = new RedisClient("127.0.0.1", 6379, "12345", 10))
{
//删除当前数据库中的所有Key
client.FlushDb();
//删除所有数据库中的key,慎用
//client.FlushAll();
//统计网站访问数量、当前在线人数、微博数、粉丝数等,全局递增ID等
#region 设置key的value
client.FlushDb();
client.Set<string>("name", "测试数据123");
Console.WriteLine("错误输出");
Console.WriteLine(client.GetValue("name"));
Console.WriteLine("正确输出");
Console.WriteLine(client.Get<string>("name"));
Console.WriteLine(JsonConvert.DeserializeObject<string>(client.GetValue("name")));
//client.Set<int>("keyInt", 123);
//Console.WriteLine("输出1");
//Console.WriteLine(client.GetValue("keyInt"));
//Console.WriteLine("输出2");
//Console.WriteLine(client.Get<int>("keyInt"));
//Console.WriteLine(JsonConvert.DeserializeObject<int>(client.GetValue("keyInt")));
#endregion
#region 设置多个key的value
//批量的写入redis key
client.FlushDb();
client.SetAll(new Dictionary<string, string> { { "id", "001" }, { "name", "world" } });
//批量读取内存中多个key的结果 如果我们获取的key不存在,程序会返回一个空的字符串,这redis不会报错
//来判断当前用户是否是老用户
var getall = client.GetAll<string>(new string[] { "id", "name", "number" });
foreach (var item in getall)
{
Console.WriteLine(item);
}
#endregion
#region 设置key的value并设置过期时间
client.FlushDb();
client.Set<string>("name", "测试数据123", TimeSpan.FromSeconds(1));
Task.Delay(1 * 1000).Wait();
Console.WriteLine(client.Get<string>("name"));
#endregion
#region 设置key的value并设置过期时间
client.FlushDb();
client.Set<string>("name", "测试数据123", 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
#region 在原有key的value值之后追加value
client.FlushDb();
client.AppendToValue("name3", "I");
client.AppendToValue("name3", " ");
client.AppendToValue("name3", "LOVE YOU");
Console.WriteLine(client.Get<string>("name3"));
#endregion
#region 获取旧值赋上新值
client.FlushDb();
client.Set("name", "测试数据123");
//获取当前key的之前的值,然后把新的结果替换进入
var value = client.GetAndSetValue("name", "world");
Console.WriteLine("原先的值" + value);
Console.WriteLine("新值" + client.GetValue("name"));
#endregion
#region 自增1,返回自增后的值
//给key为sid的键自增1 ,返回了自增之后的结果,如果键不存在,则默认将初始值赋0,自增之后就是1
client.FlushDb();
Console.WriteLine(client.Incr("sid"));
Console.WriteLine(client.Incr("sid"));
Console.WriteLine(client.Incr("sid"));
Console.WriteLine("华丽丽的结束");
Console.WriteLine(client.GetValue("sid"));
//每次通过传递的count累计,count就是累加的值
client.FlushDb();
client.IncrBy("sid", 2);
Console.WriteLine(client.Get<string>("sid"));
client.IncrBy("sid", 100);
Console.WriteLine("最后的结果***" + client.GetValue("sid"));
#endregion
#region 自减1,返回自减后的值
client.FlushDb();
Console.WriteLine(client.Decr("sid"));
Console.WriteLine(client.Decr("sid"));
Console.WriteLine(client.Decr("sid"));
Console.WriteLine("最后的结果" + client.GetValue("sid"));
//通过传入的count去做减肥 之前的结果-count
client.DecrBy("sid", 2);
Console.WriteLine("最终的结果" + client.GetValue("sid"));
#endregion
#region add 和set 的区别?
client.FlushDb();
//当使用add 方法去操作redis的时候,如果key存在的话,则不会再次进行操作 返回false 如果操作成功返回true
Console.WriteLine(client.Add("name1", "world"));
//用add的时候帮你去判断如果有则不进行操作,如果没有则写,它只能写新值,不能修改
Console.WriteLine(client.Add("name1", "你很好world"));
Console.WriteLine(client.Get<string>("name1"));
//使用set去操作 redis的时候,如果key不存在则写入当前值,并且返回true,通过存在,则对之前的值进行了一个替换 返回操作的结果
Console.WriteLine(client.Set("name2", "world"));
Console.WriteLine(client.Set("name2", "你很好world"));
Console.WriteLine(client.Get<string>("name2"));
#endregion
}
注意:尽量不是要使用GetValue,这个api的返回值是带有双引号的内容,那是因为redis默认将数据进行了序列化。这里推荐使用Get泛型的方式进行获取,这里特指的是string类型的数据。而对Int类型的数据,这里返回的结果是一致的。
自减的情况我们可以使用在减库存的场景。set和add的区别:add只做新增的工作,set既能够新增又能够改变。
抢购前景模拟代码:
public static void Show(string id, int minute)
{
#region 自减1,返回自减后的值
//开启10个线程去抢购
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, "12345", 10))
{
//本来是二步走
//1 订单+1
//2 库存-1 //同一个时间片。只会执行一条指令
var num = client.Decr("Stock");
if (num < 0)
{
Console.WriteLine(name + "抢购失败");
}
else//>=0
{
Console.WriteLine(name + "**********抢购成功***************");
client.Incr("Order");
}
}
});
Thread.Sleep(10);
}
}
Thread.Sleep(10);
}
Console.ReadLine();
#endregion
}
//////命令行参数启动
////dotnet RedisSeckill.dll --id=1 minute=03
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, "12345", 10))
{
//首先给数据库预支了秒杀商品的数量,订单数初始为0
client.Set<int>("Stock", 10);
client.Set<int>("Order", 0);
}
Seckill.Show(id, minute);
//多个用户抢购结束之后,订单数肯定是10,stock变成了-30,一共抢购了40次,10次成功,30次失败。
在redis内部进行string类型数据存储时,内部有两种数据类型,分别是短数据类型、长数据类型。短数据类型存储时长度是受限制的,长数据类型内部会在string实际长度基础上进行额外空间的开辟,进行空间的预留,这就浪费了数据存储空间。这就是string类型的缺陷。
Redis之品鉴之旅(一)的更多相关文章
- Redis之品鉴之旅(七)
分布式锁 1)阻塞锁: 尝试在redis中创建一个字符串结构缓存,方法传入的key,value为锁的过期时间timeout的时间戳. 若redis中没有这个key,则创建成功(即抢到锁),然后立即返回 ...
- Redis之品鉴之旅(六)
持久化 快照的方式(RDB) 文件追加方式(AOF) 快照形式: save和bgsave能快速的备份数据.但是.........., Save命令:将内存数据镜像保存为rdb文件,由于redis是单线 ...
- Redis之品鉴之旅(五)
Redis事务 原子性:就是最小的单位 一致性:好多命令,要么全部执行成功,要么全部执行失败 隔离性:一个会话和另一个会话之间是互相隔离的 持久性:执行了就执行了,数据保存在硬盘上 典型例子:银行转账 ...
- Redis之品鉴之旅(二)
2)hash类型,上代码 using (RedisClient client = new RedisClient("127.0.0.1", 6379, "12345&qu ...
- Redis之品鉴之旅(四)
发布订阅,简单场景下的发布订阅完全可以使用. 可以简单的理解,将一个公众号视为发布者,关注公众号的人视作订阅者,公众号发布一条文章或者消息,凡事订阅公众号的都可以收到消息.一个人可以订阅多个公众号,一 ...
- Redis之品鉴之旅(三)
3)Set,可以去重的.无序的集合.可以取交集.并集.zset(sorted set),有序的.去重的集合,排序不是根据value排序,而是根据score排序. using (RedisClient ...
- tomcat+nginx+redis实现均衡负载、session共享(二)
今天我们接着说上次还没完成session共享的部分,还没看过上一篇的朋友可以先看下上次内容,http://www.cnblogs.com/zhrxidian/p/5432886.html. 1.red ...
- tomcat+nginx+redis实现均衡负载以及session共享
1.redis简介及下载安装 作为这次的主角,相信大家对redis应该都一定印象,redis是一款开源的高性能key-value数据库,拥有丰富的键值储存类型,并提供多种语言的API. 与一般数据库不 ...
- 配置Nginx与tomcat负责均衡集群,
今天主要说说,nginx如何配置tomcat集群,首先我们先介绍一下各个软件: 一: 1.Nginx介绍: 下载地址:http://nginx.org/en/download.html nginx这个 ...
随机推荐
- 解决springboot在mac电脑下启动过慢的问题
自从用了mac以后,springboot启动的时候一直卡在build环节10多秒 但是在linux和Windows环境下,启动只要6秒,后面查看了一下其他 人也遇到这种问题,原来是需要在hosts文件 ...
- C# Unity容器的使用
最简单的使用方式(记得安装Unity NuGet包呀) Console.WriteLine("***************Unity容器的初步应用***************" ...
- 使用Eclipse搭建SSM框架(Spring + Spring MVC + Mybatis)
1.创建项目 1)打开Eclipse,点击File --> New --> Other 2)输入maven,找到Maven Project 3)然后一直按Next,直到出现一下界面: 4) ...
- C++、Java、Python、Linux、Go、前端、算法,慕课资料分享
C++.Java.Python.Linux.Go.前端.算法,慕课资料分享 微信公众号:大道同行JAVA 如有问题或建议,请后台留言,我会尽力解决你的问题. 前言 又见面了.废话不多说,最近多了一些在 ...
- java 查询当天0点0分0秒
由于业务需求,要计算客户今日收益,本周本月,本年等收益, 1.查询当天0点0分0秒 2.查询本月一号0点0分0秒 ...... Calendar calendar = Calendar.getInst ...
- TypeScript 中枚举类型的理解?应用场景?
一.是什么 枚举是一个被命名的整型常数的集合,用于声明一组命名的常数,当一个变量有几种可能的取值时,可以将它定义为枚举类型 通俗来说,枚举就是一个对象的所有可能取值的集合 在日常生活中也很常见,例如表 ...
- 使用 Dockerfile 自定义 Nginx 镜像
一般来说,自定义Nginx只需要把静态文件放到镜像里就可以了,不需要重写 CMD 与 ENTRYPOINT.但是,如果的确需要在 Nginx 启动前执行一些操作,就需要重写 CMD 了,如果写成下边就 ...
- Tricks
由于本人着实有些菜,因此在此积累一些巧妙的 \(Tricks\) ,以备不时之需... 与其说是 \(Tricks\) 不如说是学习笔记?? 数学 组合数 常见的数列 斐波那契数列 图论 树论 \(P ...
- noip模拟测试18
打开比赛第一眼--超级树? 点开--原题 百感交集-- 欣喜于发现是半年前做过两遍的原题 紧张于如果A不了比较尴尬 绝望于发现根本不会做了 瞟了一眼t1,瞅了一眼t2,嗯--开始搞t3 10分钟打完暴 ...
- IT人计算机网络浅析
LAN: 局域网 local Area Network WAN: 广域网 Wide Area Network WAN = LAN +LAN+....+LAN 多个LAN 组成 WAN OSI 七层协议 ...