什么!Redis不会用!看完这个你就是Redis大牛了!

Posted 还怕大雨吗-

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了什么!Redis不会用!看完这个你就是Redis大牛了!相关的知识,希望对你有一定的参考价值。

redis

1.nosql

联系作者:扣扣  190557020

什么是nosql:

NoSQL,指的是非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。

NoSQL用于超大规模数据的存储。(例如谷歌或Facebook每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。

常用的NoSQL数据库,Redis,MongoDB,Es,

大致分为以下几种:

  1. 键值数据库

  2. 列组数据库

  3. 文档数据库

  4. 图形数据库

2.安装redis

windos下安装redis

直接下载直接解压即可用

下载地址:链接: https://pan.baidu.com/s/1chv4tPBCI6tV3HHIb-92Tw 提取码: g9n3

配置一个快速启动的脚本

创建redis-start.bat文件,右击编辑,输入 redis-server redis.windows.conf 保存即可

双击启动

默认端口为6379

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LctcMVXJ-1627702088495)(H:\\技术点\\redis\\redis-这一篇就够了.assets\\1627566370994.png)]

redis-cli.exe 文件是命令行操作,输入keys * 查看所有键

出现以上界面,windows下的Redis就算安装完成了,

linux下本地安装redis

路灯

https://www.cnblogs.com/xsge/p/13841875.html

Docker下安装redis:

记得关闭防火墙/开放端口

centos7 下的 docker安装redis

#启动docker
systemctl start docker

#查找redis的镜像
docker search redis

# 下载指定版本,,
docker pull redis:6.0-rc

此处需要联网

#查看docker里的镜像
docker images
#创建挂载目录,配置文件需要将下载一份配置上去,redis.conf,
mkdir -p /home/redis/myredis
#conf文件的目录

//创建data
cd /home/redis/myredis
mkdir data

redis各版本配置文件下载:https://redis.io/topics/config

安装的命令

docker run  -p 6379:6379 \\
--name niuzi_redis -v /home/redis/myredis/myredis.conf:/etc/redis/redis.conf \\
-v /home/redis/myredis/data:/data -d redis redis-server /etc/redis/redis.conf \\
--appendonly yes \\
redis:6.0-rc


#二选一,下面这个使用的默认的配置
docker run -itd --name redis6 -p 6379:6379 redis:6.0-rc

–restart=always 总是开机启动

-p 6379:6379 将6379端口挂载出去

–name 给这个镜像取一个名字

-v 数据卷挂载

/home/redis/myredis/myredis.conf:/etc/redis/redis.conf

这里是将 liunx 路径下的myredis.conf 和redis下的redis.conf 挂载在一起。
/home/redis/myredis/data:/data 这个同上

-d redis 表示后台启动redis

redis-server /etc/redis/redis.conf 以配置文件启动redis,加载容器内的conf文件,最终找到的是挂载的目录 /etc/redis/redis.conf 也就是liunx下的/home/redis/myredis/myredis.conf

–appendonly yes 开启redis 持久化

#查看是否安装成功
docker ps -a 

#运行redis
docker start niuzi_redis  #可以是名称,也可以是最前面的id

#打开redis命令测试
docker exec -it redis6-two redis-cli

#输入测试命令
keys *

出现以下界面则表示安装成功

3.redis相关知识

端口号默认是6379

一共有16个数据库,

redis是单线程

redis可以进行持久化操作

单线程+多路io复用

原子性 所谓原子操作是指不会被线程调度机制打断的操作

​ 这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。

(1)在单线程中, 能够在单条指令中完成的操作都可以认为是"原子操作",因为中断只能发生于指令之间。

(2)在多线程中,不能被其它进程(线程)打断的操作就叫原子操作。

Redis单命令的原子性主要得益于Redis的单线程。

4.常用五大数据类型

1.对key进行操作

#查看所有key
keys *

#判断该key是否存在 返回1则存在,0则不存在
exists key 

#查看key是什么类型
type key

#删除key
del key

#根据value选择非阻塞删除
unlink key

#设置key的过期时间,10描
expire key 10

#查看还有多少秒过期  -1永不过期,-2表示已过期
ttl key 

#切换数据库
select 0/1/2/3/....

#查看当前数据库有多少数量的key
dbsize


!!!!!!慎用!!!!!

#清空当前库
flushdb

#通杀全部库
flushall


2.String类型

String是redis最基本的类型,是非常强大的

String类型是二进制安全的,意味着他可以保存任何数据,比如序列化

一个redis中字符串value最多可以是512M

#存入值,重复往key中存储会覆盖值
set key value

#获取值
get key

#追加值
append key value

#获取长度
strlen

#当key不存在的时候设置key的值
setnx key value

3. List类型

单键多值

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)

它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差

#从表头添加或表尾
lpush/rpush  key value,key value

#从表头或表尾吐出一个值,
lpop/rpop key  #键在则在,键光则亡

#根据下标范围获取值  多用于 0 -1  获取全部
lrange key start stop

#在<value>的后面插入<newvalue>插入值
linsert <key>  before <value><newvalue>

#从左边删除n个value(从左到右)
lrem <key><n><value>

#将列表key下标为index的值替换成value
lset<key><index><value>

4.set类型

set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。

#将一个或多个 member 元素加入到集合 key 中,已经存在的 member 元素将被忽略
sadd <key><value1><value2> ..... 

#取出该集合的所有值
smembers <key>

#判断集合<key>是否为含有该<value>值,有1,没有0
sismember <key><value>

#返回该集合的元素个数。
scard<key>

#删除集合中的某个元素。
srem <key><value1><value2> .... 

#随机从该集合中吐出一个值。
spop <key>

#随机从该集合中取出n个值。不会从集合中删除 。
srandmember <key><n>

#返回两个集合的交集元素。
sinter <key1><key2>

#返回两个集合的并集元素。
sunion <key1><key2>

#返回两个集合的差集元素(key1中的,不包含key2中的)
sdiff <key1><key2>

Java中HashSet的内部实现使用的是HashMap,只不过所有的value都指向同一个对象。Redis的set结构也是一样,它的内部也使用hash结构,所有的value都指向同一个内部值

5.hash类型

Redis hash 是一个键值对集合。

Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。

类似Java里面的Map<String,Object>

用户ID为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,

#给<key>集合中的  <field>键赋值<value>
hset <key><field><value>

#从<key1>集合<field>取出 value
hget <key1><field> 

#批量设置hash的值
hmset <key1><field1><value1><field2><value2>... 

#查看哈希表 key 中,给定域 field 是否存在。 
hexists<key1><field>

#列出该hash集合的所有field
hkeys <key>

#列出该hash集合的所有value
hvals <key>

Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。

6.zset有序集合

Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。

不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了 。

因为元素是有序的, 所以你也可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。

访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。

多用于,点赞之类的

#将一个或多个 member 元素及其 score 值加入到有序集 key 当中。
zadd  <key><score1><value1><score2><value2>#返回有序集 key 中,下标在<start><stop>之间的元素
#带WITHSCORES,可以让分数一起和值返回到结果集。
zrange <key><start><stop>  [WITHSCORES]   

#返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。
zrangebyscore key minmax [withscores] [limit offset count]
 
#同上,改为从大到小排列。 
zrevrangebyscore key maxmin [withscores] [limit offset count]               

#为元素的score加上增量
zincrby <key><increment><value>    

#删除该集合下,指定值的元素 
zrem  <key><value>

#统计该集合,分数区间内的元素个数
zcount <key><min><max> 

#返回该值在集合中的排名,从0开始
zrank <key><value>

SortedSet(zset)是Redis提供的一个非常特别的数据结构,一方面它等价于Java的数据结构Map<String, Double>,可以给每一个元素value赋予一个权重score,另一方面它又类似于TreeSet,内部的元素会按照权重score进行排序,可以得到每个元素的名次,还可以通过score的范围来获取元素的列表

zset底层使用了两个数据结构

(1)hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值。

(2)跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表。

7.新数据类型Bitmaps

进行位操作,

合理地使用操作位能够有效地提高内存使用率和开发效率。

(1) Bitmaps本身不是一种数据类型, 实际上它就是字符串(key-value) , 但是它可以对字符串的位进行操作。

(2) Bitmaps单独提供了一套命令, 所以在Redis中使用Bitmaps和使用字符串的方法不太相同。 可以把Bitmaps想象成一个以位为单位的数组, 数组的每个单元只能存储0和1, 数组的下标在Bitmaps中叫做偏移量。

#添加数据-设置Bitmaps中某个偏移量的值(0或1)
setbit key <key><offset><value>

#获取偏移量
get <key><offset>

统计**字符串**被设置为1的bit数。一般情况下,给定的整个字符串都会被进行计数,通过指定额外的 start 或 end 参数,可以让计数只在特定的位上进行。start 和 end 参数的设置,都可以使用负数值:比如 -1 表示最后一个位,而 -2 表示倒数第二个位,start、end 是指bit组的字节的下标数,二者皆包含

bitcount<key>[start end] #统计字符串从start字节到end字节比特值为1的数量

start和end代表起始和结束字节数

bitop是一个复合操作, 它可以做多个Bitmaps的and(交集) 、 or(并集) 、 not(非) 、 xor(异或) 操作并将结果保存在destkey中。

bitop  and(or/not/xor) <destkey> [key…]

与set对比

当网站用户访问量大的时候可以使用bitmaps,可以节省内存

当网站访问量较小的时候是不如set的

8.新数据类型HyperLogLog

基数统计的算法

在工作当中,我们经常会遇到与统计相关的功能需求,比如统计网站PV(PageView页面访问量),可以使用Redis的incr、incrby轻松实现。

但像UV(UniqueVisitor,独立访客)、独立IP数、搜索记录数等需要去重和计数的问题如何解决?这种求集合中不重复元素个数的问题称为基数问题。

解决基数问题有很多种方案:

(1)数据存储在mysql表中,使用distinct count计算不重复个数

(2)使用Redis提供的hash、set、bitmaps等数据结构来处理

以上的方案结果精确,但随着数据不断增加,导致占用空间越来越大,对于非常大的数据集是不切实际的。

能否能够降低一定的精度来平衡存储空间?Redis推出了HyperLogLog

Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。

在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

什么是基数?

比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。

#添加指定元素到 HyperLogLog 中
pfadd <key>< element> [element ...]

#将所有元素添加到指定HyperLogLog数据结构中。如果执行命令后HLL估计的近似基数发生变化,则返回1,否则返回0。
#统计数量
pfcount <key>
#pfmerge 将一个或多个HLL合并后的结果存储在另一个HLL中
#将k1 k2的值合并放在k3中
pfmerge k3 k1 k2

9.新数据类型Geographic

Redis 3.2 中增加了对GEO类型的支持。GEO,Geographic,地理信息的缩写。该类型,就是元素的2维坐标,在地图上就是经纬度。redis基于该类型,提供了经纬度设置,查询,范围查询,距离查询,经纬度Hash等常见操作。

geoadd<key>< longitude><latitude><member> [longitude latitude member...] 
#实例

geoadd china:city 121.47 31.23 shanghai
geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen 116.38 39.90 beijing

两极无法直接添加,一般会下载城市数据,直接通过 Java 程序一次性导入。

有效的经度从 -180 度到 180 度。有效的纬度从 -85.05112878 度到 85.05112878 度。

当坐标位置超出指定范围时,该命令将会返回一个错误。

已经添加的数据,是无法再次往里面添加的。

南极与北极不可添加

geopos  <key><member> [member...]  #获得指定地区的坐标值


#获取两个地区的直线距离是多少
geodist <key><member1><member2>  [m|km|ft|mi ] 

单位:

m 表示单位为米[默认值]。

km 表示单位为千米。

mi 表示单位为英里。

ft 表示单位为英尺。

如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位

#以给定的经纬度为中心,找出某一半径内的元素
georadius <key>< longitude><latitude>radius  m|km|ft|mi 

5.redis发布和订阅

什么是发布和订阅

Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。

Redis 客户端可以订阅任意数量的频道

当给这个频道发布消息后,消息就会发送给订阅的客户端

命令行实现

打开2个客户端,

1、 打开一个客户端订阅channel1

SUBSCRIBE channel1

2丶打开另一个客户端,给channel1发布消息hello

publish channel1 hello

打开第一个客户端可以看到发送的消息,发布的消息没有持久化,如果在订阅的客户端收不到hello,只能收到订阅后发布的消息

6.安装redis可视化

在开发与练习中,频繁的使用命令是不可行的,为了提升开发效率,更直观的将数据展示出来,需要安装一个redis的可视化

软件安装 RedisDesktopManager

链接:https://pan.baidu.com/s/14rpZn6ZEEfpSWT5bOJJEYg
提取码:t16i

傻瓜式安装–一直下一步,安装链接根据个人修改

启动软件

创建redis链接

显示成功链接后点击ok

可以直观的看到,我们有16个数据库。每个数据库存放了什么,值是什么

7.SpringBoot操作redis

1.创建springboot项目

2.添加依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>

3.redis的yml配置文件

redis:
  # redis数据库索引(默认为0),我们使用索引为3的数据库,避免和其他数据库冲突
  database: 3
  # redis服务器地址(默认为loaclhost)
  host: 192.168.73.12
  # redis端口(默认为6379)
  port: 6379
  # redis访问密码(默认为空)
  password: pwd123
  # redis连接超时时间(单位毫秒)
  timeout: 0
  # redis连接池配置
  pool:
    # 最大可用连接数(默认为8,负数表示无限)
    max-active: 8
    # 最大空闲连接数(默认为8,负数表示无限)
    max-idle: 8
    # 最小空闲连接数(默认为0,该值只有为正数才有用)
    min-idle: 0
    # 从连接池中获取连接最大等待时间(默认为-1,单位为毫秒,负数表示无限)
    max-wait: -1

这里我们使用的最终yml为

redis:    #redis其他的都使用默认配置,也可以不配,全部使用默认配置,这里为了直观的学习固修改host和port
  host: 127.0.0.1 #/localhost
  # redis端口(默认为6379)      
  port: 6379
server:
  port: 9001    #端口号
spring:
  application:
    name: spring-boot-redis-0730  #项目名称

4.注入模板

	@Resource
    private StringRedisTemplate stringRedisTemplate;

//    @Resource			在此工程中使用stringredistemplate
//    private RedisTemplate redisTemplate;

StringredisTemplate 与 RedisTemplate 的区别

Resource 与 Autowried的区别

5. 操作模版

String常用的模板操作
 	//存入redis
	@Test
    void addStringRedis() {
   	 ValueOperations<String, String> StringRedis 
        = stringRedisTemplate.opsForValue();
            StringRedis.set("job","male");
            StringRedis.set("jack","male");
            StringRedis.set("lisa","female");
            StringRedis.set("alili","female");
    }
	/**
     * @description 根据key获取值
     * @params []
     * @return void
     * @author -还怕大雨吗
     * @date 2021/7/30 12:18
     */
    @Test
    void getStringredis(){
        ValueOperations<String, String> StringRedis = stringRedisTemplate.opsForValue();
        //根据key获取值
        String job = StringRedis.get("job");
        System.out.println("job = " + job);
    }

	//job = male
/**
     * @description 给key设置过期时间,使用timeunit函数
     * @params []
     * @return void
     * @author -还怕大雨吗
     * @date 2021/7/30 12:23
     */
    @Test
    void setExpireRedis(){
        stringRedisTemplate.opsForValue().set("job","male",30,TimeUnit.SECONDS);
    }

List常用模板操作
  /**
     * @description 对list进行左右插入操作
     * @params []
     * @return void
     * @author -还怕大雨吗
     * @date 2021/7/30 14:43
     */
    @Test
    void setRedisList(){
        //  在变量左边添加元素值。右边同理,只是方法名换成rightPush
//        stringRedisTemplate.opsForList().rightPush()
        //批量添加时,直接在后面拼接,例如
//		  stringRedisTemplate.opsForList().leftPush("list","a","b","c");
       	//也可以直接将集合放进去
//        stringRedisTemplate.opsForList().leftPush("list",List对象);
        stringRedisTemplate.opsForList().leftPush("list","a");
        stringRedisTemplate.opsForList().leftPush("list","b");
        stringRedisTemplate.opsForList().leftPush("list","c");
    }

/**
     * @description Ipuest
     * @params []
     * @return void
     * @author -还怕大雨吗
     * @date 2021/7/30 14:50
     */
    @Test
    void Ipuest(){
        //  如果存在集合则添加元素。
        stringRedisTemplate.opsForList().leftPushIfPresent("presentList","o");
        List<String> list = stringRedisTemplate.opsForList().range("presentList", 0, -1);
        System.out.println("通过leftPushIfPresent(K key, V value)方法向已存在的集合添加元素:" + list);
    }
 // size(K key)
//获取集合长度。
    long listLength = redisTemplate.opsForList().size("list");
    System.out.println("通过size(K key)方法获取集合list的长度为:" + listLength);
// 16、rightPop(K key)
        // 移除集合中右边的元素。
		// rightPop(K key, long timeout, TimeUnit unit)
        // 移除集合中右边的元素在等待的时间里,如果超过等待的时间仍没有元素则退出
        String list = stringRedisTemplate.opsForList().rightPop("list");
        System.out.print("通过rightPop(K key)方法移除的元素是:" + list);
        List<String> list1 = stringRedisTemplate.opsForList().range("list", 0, -1);
        System.out.println(",剩余的元素是:" + list1);
/**
     * @description 获取全部的数据
     * @params []
     * @return void
     * @author -还怕大雨吗
     * @date 2021/7/30 14:46
     */
    @Test
    以上是关于什么!Redis不会用!看完这个你就是Redis大牛了!的主要内容,如果未能解决你的问题,请参考以下文章

Redis是多线程还是单线程?看完“手撕”面试官

看完这个还不了解redis的SDS,半夜你来扒我家墙头

看完这篇Redis缓存三大问题,够你和面试官battle几回合了

看完这篇,以后再也不怕Redis面试了!

为啥redis 访问慢

看完这篇文章,还不会 Redis 的高级特性,你来打我!