redis是一个,nosql,key-value,非关系型的,内存运行,单进程单线程的,可持久化,支持分布式的,实现缓存,数据库技术。
Not Only Structured query language,不仅结构化查询语言。
SQL结构化查询语言。说明redis可以存储非结构化数据。
redis存储数据的基本结构 键值对 key-value-一条数据。非结构化数据的一种处理结构方式,很多技术在存储非结构化数据时都是用key-value结构
无法体现数据之间的相关关系。原因为大量非结构化数据存储。结构不允许key-value,想要使用多个key-value之间的关系,人为的设计多个key-value。
redis启动之后,是在内存运行,内存存储数据的一个数据库技术,并且一个redis启动的服务进程中,只存在一个线程来处理并发。
为什么不使用多线程,性能,并发更高吗?
如果redis技术以多线程结构实现的,性能并发确实会变高。
内存运行:数据从内存读写的
优点:速度快
缺点:断电丢失数据,高可靠性比较低
相比硬盘,容量比较小
很多能做缓存的技术,都是基于内存的,rabbitmq消息队列缓存。可以通过支持持久化,极大降低内存断电丢失数据造成的损失
redis支持2种持久化方式,可以根据使用场景选择持久化方式,也可以在不需要持久化时,将持久化关闭。
如果开启了持久化,当redis出现宕机故障,内存数据肯定丢失,下次重启会因为持久化数据的存在,重新加载到内存中。
单进程,单线程--性能瓶颈在一个redis服务的网络带宽,带宽有限
内存运行--单个redis服务容量有限。
redis支持分布式的(一个人不行了,多个人来帮忙)
单个节点会有很多瓶颈,网络带宽,内存容量
可以引入一个redis分布式集群
redis的应用场景非常丰富,缓存为主。如果使用redis实现easymall的缓存
缓存逻辑。
可以在一个ssm框架的结构中,在业务层编写操作redis的代码。
1 判断缓存存在
2 如果存在直接使用缓存数据,调用持久层,获取连接,发送sql,拿到返回结果封装对象这几步完全不用做了。
3 如果不存在,希望下次访问该商品能从缓存获取,先到数据库查一次,在返回给客户端之前,存储到redis缓存一份。
REDIS五种数据结构和命令
2020年2月12日
14:41
set/get非常常用的字符串类型数据的写/覆盖,和读
以下的命令是不区分数据类型(key-value类型是总类型,在redis中对于
value数据结构是严格的区分的,存在五种不同的value数据类型)
表示在客户端查看当前redis服务端内存中所有的数据key值。
127.0.0.1:6379> keys *
1) "location"
2) "gender"
3) "age"
4) "name"
127.0.0.1:6379>
将已有的数据返回,么有数据时,返回空。这里返回的都是内存中保存的
数据key值
不支持分布式结构。不能通过一个keys * 从一个redis服务中查看其它redis数据
生产环境(客户使用环境)使用keys *不合理,造成读数据阻塞(一次读太多数据)
表示要查看一下对应的key值数据是否在redis内存中存在。
127.0.0.1:6379> keys *
1) "location"
2) "gender"
3) "age"
4) "name"
127.0.0.1:6379> exists age
(integer) 1
127.0.0.1:6379> exists haha
(integer) 0
如果判断存在的数据,有读的操作,比如字符串类型的get,不需要exists的存在了呢?
不可以,因为使用读判断存在,浪费了读数据的带宽。而且redis 最新版本一个value数据可以
达到1GB大小。
在redis中,可以根据需求对写入的数据设置超时时间,一旦到达超时条件
将会在内存中把数据删除,expire 对某个key的数据做秒单位的超时,pexpire对key
值做毫秒单位的超时。没有使用相关超时的数据写入时,默认是永久数据。
127.0.0.1:6379> expire location 5
(integer) 1
127.0.0.1:6379> keys *
1) "gender"
2) "age"
3) "name"
在执行设置了超时时间的key值上,查看这个key的剩余时间。
ttl操作一个key能够看到剩余时间单位是秒,pttl看得是毫秒。
127.0.0.1:6379> expire name 100
(integer) 1
127.0.0.1:6379> ttl name
(integer) 89
127.0.0.1:6379> pttl name
(integer) 83322
127.0.0.1:6379>
del可以对指定的key-value进行删除操作。
127.0.0.1:6379> keys *
1) "gender"
2) "age"
127.0.0.1:6379> del gender
(integer) 1
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379>
redis支持持久化,将内存数据,输出到持久化文件,内存数据保存在磁盘上。
redis重新启动时自动加载保存的持久化文件,将数据恢复回来。
save命令的调用,就是将内存数据输出到持久化文件中保存。
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> get age
"18"
127.0.0.1:6379> save
OK
127.0.0.1:6379>
将redis服务端关闭 ctrl+c;内存中一定不会再存在age的数据。但是只要重新启动,由于持久化文件中存在数据,会启动时恢复到内存中。
冲刷所有。将当前redis服务的内存数据和持久化文件中的数据全部清空。
尽可能只在测试环境使用,不要到生产环境。
redis是以key-value结构存储数据的,但是根据不同的应用场景,可以使用完全不同的value结构存储数据。包括:String字符串,Hash,List链表,Set集合,ZSet有序集合
redis中可以对字符串类型进行写操作调用set命令,也可以在已有数据时,对数据覆盖操作。在redis的大量命令都可以携带很多不同的参数选项。使用详细的选项和参数,可以从redis官网去查看 连接
EX:可以在set时直接设置超时秒数
PX:可以在set时直接设置超时毫秒数
127.0.0.1:6379> set bomb tnt EX 50
OK
127.0.0.1:6379> ttl bomb
(integer) 46
127.0.0.1:6379>
NX:在执行set时,会判断redis中有没有该key值,如果有则无法set,没有则可以set成功。表示,只有第一个set数据的客户端可以成功,后续都会失败。
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> set age 22 NX
(nil)
127.0.0.1:6379> set name wanglaoshi NX
OK
127.0.0.1:6379>
XX:在执行set时,会判断redis中有没有key值,有的时候才会set成功,没有则不成功。表示,使用XX的客户端没有新建的权限。
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> set gender male XX
(nil)
127.0.0.1:6379> set age 55 XX
OK
从redis中读取key值的value数据。在redis中value最大数据长度1GB。
127.0.0.1:6379> get age
"55"
127.0.0.1:6379>
如果想要删除字符串类型数据就是调用del命令
执行计步器,可以增加数值,减少数值。对应value字符串数据必须是纯数字
127.0.0.1:6379> incr age
(integer) 56
127.0.0.1:6379> decr age
(integer) 55
127.0.0.1:6379> incrby age 10
(integer) 65
127.0.0.1:6379> decrby age 20
(integer) 45
常见的应用使用计步器:
记录排队人数(拿号,自增,叫号后,前剩余人数自减);
在线人数统计(每秒钟上下变动)
一般使用String类型的value数据实现 缓存的功能。并且可以利用代码的序列化和反序列化的方法,将对象序列化为字符串(user-->{“userName”:“wanglaoshi”}).在easymall中使用序列化将product对象变成json,以商品id作为唯一key值操作商品在redis的缓存数据。
hash在redis中底层双层map形式存在,key-value是map,value在hash结构中又是一个map。所以他可以对应对象的数据结构。
在redis中创建一个key值为key 对应第二层map的key为field,
第二层map的value为value
127.0.0.1:6379> hset user age 18
(integer) 1
127.0.0.1:6379> hset user name wanglaoshi
(integer) 1
127.0.0.1:6379> hset user gender male
(integer) 1
127.0.0.1:6379> keys *
1) "age"
2) "user"
127.0.0.1:6379>
由于hash结构双层map,hget可以读取到一个属性的值,指定某个key的 某个属性读取
127.0.0.1:6379> hget user name
"wanglaoshi"
127.0.0.1:6379> hget user age
"18"
127.0.0.1:6379>
hkeys key从key值的hash数据结构中将所有的field属性名称返回
hvals key 从key的hash数据结构中将所有的field的值返回
127.0.0.1:6379> hkeys user
1) "age"
2) "name"
3) "gender"
127.0.0.1:6379> hvals user
1) "18"
2) "wanglaoshi"
3) "male"
127.0.0.1:6379>
如果想将整个hash结构删掉,直接调用del 全部删除
如果删除的是一个hash结构中的某个属性和值,
hdel key field
127.0.0.1:6379> hkeys user
1) "age"
2) "name"
3) "gender"
127.0.0.1:6379> hdel user age
(integer) 1
127.0.0.1:6379> hkeys user
1) "name"
2) "gender"
127.0.0.1:6379>
也可以像String一样,执行某个项目中的缓存逻辑。不同环境使用不同结构,有不同的效果。
例如,缓存数据对象的结构比较复杂,属性不仅仅是Integer String 还有数组,list,还有set,优先使用String类型,如果对象属性简单可以使用hash(造成代码编写复杂)
list底层双向链表,可以从头和尾部处理数据,实现队列的结构(就为了处理消息队列逻辑)。
l/r 表示左和右。lpush从链表头部,插入数据,rpush从链表的尾部,插入数据
127.0.0.1:6379> lpush student wangcuihua
(integer) 1
127.0.0.1:6379> lpush student liuyoucai
(integer) 2
127.0.0.1:6379> rpush student zhangshoufu
(integer) 3
127.0.0.1:6379>
行程链表结构顺序:
liuyoucai
wangcuihua
zhangshoufu
可以对一个list链表中的元素范围内的数据读取返回。
lrange student 起始下标 结束下标
127.0.0.1:6379> lrange student 0 4
1) "liuyoucai"
2) "wangcuihua"
3) "zhangshoufu"
127.0.0.1:6379> lrange student 1 4
1) "wangcuihua"
2) "zhangshoufu"
127.0.0.1:6379>
有时候,咱们并不会确定不知道元素的个数,要想查看所有的元素可以使用-1的end结尾
表示一直到尾部。start=0 end=-1 就可以查询一个list所有内容
127.0.0.1:6379> lrange student 0 -1
1) "liuyoucai"
2) "wangcuihua"
3) "zhangshoufu"
127.0.0.1:6379>
不建议使用,双向链表操作最有效,速度最快是对头尾的操作。
lset可能从中间操作链表,效率非常低
对list的某个下标为index的元素值,做修改。
127.0.0.1:6379> lrange student 0 -1
1) "liuyoucai"
2) "wangcuihua"
3) "zhangshoufu"
127.0.0.1:6379> lset student 1 haha
OK
127.0.0.1:6379> lrange student 0 -1
1) "liuyoucai"
2) "haha"
3) "zhangshoufu"
127.0.0.1:6379>
rpop从链表的尾部删除元素,并且将删除的元素值返回
lpop从链表的头部删除元素,将元素值返回(remove)
127.0.0.1:6379> lrange student 0 -1
1) "liuyoucai"
2) "haha"
3) "zhangshoufu"
127.0.0.1:6379> rpop student
"zhangshoufu"
127.0.0.1:6379> lpop student
"liuyoucai"
127.0.0.1:6379> lrange student 0 -1
1) "haha"
127.0.0.1:6379>
初始目的就是利用list的类型实现排队队列的处理逻辑,先来先得,先到先处理。
可以在元素中封装一些消息属性,先进入队列,优先被pop出去进行处理。
easymall使用list数据,实现高并发争抢线程资源的权限设置,解决防止线程安全的出现。
可以将不同的,不重复的元素值,放到一个没有顺序概念的集合中,实现value数据在redis的管理
登录系统时,给用户帖的标签。例如:
登录一些明日头条这种推荐文件,推荐网站的系统,注册后选择自己兴趣爱好:军事,数学,历史,天文,登陆后会跟你你选择的内容,随机推荐不同的文章。
直播网站:lol 王者荣耀 dota2其他,根据兴趣推送相关直播
还可以实现好友保存,计算共同好友
新增元素到集合中。
127.0.0.1:6379> sadd favor math english geo
(integer) 3
随机在key对应set集合中选取count个元素。
127.0.0.1:6379> srandmember favor
"english"
127.0.0.1:6379> srandmember favor 2
1) "math"
2) "geo"
可以对集合中某个元素进行去除的操作,当删除成功,返回1,删除失败返回0
127.0.0.1:6379> srem favor math
(integer) 1
127.0.0.1:6379> srem favor mathdasfdads
(integer) 0
127.0.0.1:6379>
127.0.0.1:6379> sismember favor math
(integer) 0
127.0.0.1:6379> sismember favor english
(integer) 1
127.0.0.1:6379>
在set基础之上,实现了排序的方式,元素也是不可以重复,就是在元素的数据上绑定了一个
评分的数据(实际应用场景中,评分可以不同业务意义,例如点击率,例如播放量,例如投票数量等)
网站各种排名,都可以使用ZSET有序集合
视频网站:热播剧,top10。
热搜:话题搜索次数。
小说网站:订阅量排序,月票排序
可以将一个元素绑定一个分数后,写入到一个有序集合中
127.0.0.1:6379> zadd score 98 piqian
(integer) 1
127.0.0.1:6379> zadd score 97 haoxia
(integer) 1
127.0.0.1:6379> zadd score 80 caoan
(integer) 1
127.0.0.1:6379> zadd score 15000 xiaowei
(integer) 1
在有序集合中主要就是为了体现排序,所以使用命令最多的查询方式
就是排序相关内容
127.0.0.1:6379> zrank score piqian
(integer) 2
起始排名是0,可以对stop=-1查到末尾
127.0.0.1:6379> zrange score 0 -1
1) "caoan"
2) "haoxia"
3) "piqian"
4) "xiaowei"
127.0.0.1:6379>
127.0.0.1:6379> zrangebyscore score 50 200
1) "caoan"
2) "haoxia"
3) "piqian"
将元素从zset类型的数据中删除
easymall中如何使用redis的服务端,如何封装redis的客户端。java作为redis
的客户端代码,是有对应封装客户端的jar包资源的,只要在代码中引入jar包资源
就可以实现通过代码调用api的方式像在这里操作执行nosql命令一样去操作redis的数据
redis使用c语言开发的(总代码量不超过10万行,以前是说5万行。开发者完全将源码吃透),linux安装结束后,会出现几个操作redis脚本文件。
[root@10-9-39-13 redis-3.2.11]# redis-server
重新打开一个创建
[root@10-9-39-13 ~]# redis-cli
127.0.0.1:6379>
对于以上的执行命令的,自习中,执行一遍有印象即可,对于常用的set get exists expire ttl/pexpire pttl方法去调用。