redis (remote dictionary server)即远程字典服务
是一个开源的ANSI C语言编写,支持网络,可基于内存亦可持久化的日志型 Key-Value数据库 提供多语言的API
redis能干嘛?
1.内存存储,持久化,内存中是断电即失的,所以说持久化很重要(rdb,aof)
2.效率高,可以用于高速缓存
3.发布订阅系统
4.地图信息分析
5.计时器,计数器(浏览量,阅读量···)
6.···············
特性:
1.多样的数据类型
2.持久化
3.集群
4.事务
·······
Redis推荐都是在Linux服务器上搭建的,我们是基于linux学习
Windows安装
下载地址:https://github.com/MSOpenTech/redis/releases。
Redis 支持 32 位和 64 位。这个需要根据你系统平台的实际情况选择。
二、解压下载的zip包,如我解压到D:\Coding\Environment\Redis-x64-3.2.100
三、配置redis环境变量,把redis路径配置到系统变量的Path值中,如图:
四、打开一个cmd窗口,执行redis-server.exe就可以启动redis了。
五、打开一个新的cmd窗口,执行redis-cli.exe -h 127.0.0.1 -p 6379
(注意ip和port)
设置键值对 set demo 1234
取出键值对 get demo
linux安装
略
redis-benchmark
可以在Linux和Windows中都能看到,它是一个压力测试工具!
官方自带的
Redis为什么单线程还这么快?
误区1:高性能的服务器一定是多线程的?
误区2:多线程(CPU上下文会切换!)一定比单线程效率高!
核心:Redis是将所有的数据放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(CPU上下文会切换:耗时的操作!),对于内存系统来说,如果没有上下文切换效率就是最高的,多次读写都是在一个CPU上的,在内存存储数据情况下,单线程就是最佳的方案。
redis默认有16个数据库
16个数据库为:DB 0~DB 15
默认使用DB 0 ,可以使用select n
切换到DB n,dbsize
可以查看当前数据库的大小,与key数量相关。
select 0 选用0号数据库
命令:
keys *
:查看当前数据库中所有的key。
flushdb
:清空当前数据库中的键值对。
flushall
:清空所有数据库的键值对。
以下内容基本上抄的这篇博客
https://blog.csdn.net/DDDDeng_/article/details/108118544
Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型。内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区。
exists key
:判断键是否存在del key
:删除键值对move key db
:将键值对移动到指定数据库expire key second
:设置键值对的过期时间 expire hi 10 设置十秒过期type key
:查看value的数据类型90%的程序员使用redis只会用String类型!
set key value 设置一个键
get key 得到key的value
String类似的使用场景(阅读量):value除了是字符串还可以是数字,用途举例:
set view 0
incr views view +1
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
一个列表最多可以包含 2的32 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
我们list,可以看作 队列、栈、双端队列等
正如图Redis中List是可以进行双端操作的,所以命令也就分为了LXXX和RLLL两类,有时候L也表示List例如LLEN
---------------------------LPUSH---RPUSH---LRANGE------------------------------- 127.0.0.1:6379> LPUSH mylist k1 # LPUSH mylist=>{1} (integer) 1 127.0.0.1:6379> LPUSH mylist k2 # LPUSH mylist=>{2,1} (integer) 2 127.0.0.1:6379> RPUSH mylist k3 # RPUSH mylist=>{2,1,3} (integer) 3 127.0.0.1:6379> get mylist # 普通的get是无法获取list值的 (error) WRONGTYPE Operation against a key holding the wrong kind of value 127.0.0.1:6379> LRANGE mylist 0 4 # LRANGE 获取起止位置范围内的元素 1) "k2" 2) "k1" 3) "k3" 127.0.0.1:6379> LRANGE mylist 0 2 1) "k2" 2) "k1" 3) "k3" 127.0.0.1:6379> LRANGE mylist 0 1 1) "k2" 2) "k1" 127.0.0.1:6379> LRANGE mylist 0 -1 # 获取全部元素 1) "k2" 2) "k1" 3) "k3" ---------------------------LPUSHX---RPUSHX----------------------------------- 127.0.0.1:6379> LPUSHX list v1 # list不存在 LPUSHX失败 (integer) 0 127.0.0.1:6379> LPUSHX list v1 v2 (integer) 0 127.0.0.1:6379> LPUSHX mylist k4 k5 # 向mylist中 左边 PUSH k4 k5 (integer) 5 127.0.0.1:6379> LRANGE mylist 0 -1 1) "k5" 2) "k4" 3) "k2" 4) "k1" 5) "k3" ---------------------------LINSERT--LLEN--LINDEX--LSET--------------------------- 127.0.0.1:6379> LINSERT mylist after k2 ins_key1 # 在k2元素后 插入ins_key1 (integer) 6 127.0.0.1:6379> LRANGE mylist 0 -1 1) "k5" 2) "k4" 3) "k2" 4) "ins_key1" 5) "k1" 6) "k3" 127.0.0.1:6379> LLEN mylist # 查看mylist的长度 (integer) 6 127.0.0.1:6379> LINDEX mylist 3 # 获取下标为3的元素 "ins_key1" 127.0.0.1:6379> LINDEX mylist 0 "k5" 127.0.0.1:6379> LSET mylist 3 k6 # 将下标3的元素 set值为k6 OK 127.0.0.1:6379> LRANGE mylist 0 -1 1) "k5" 2) "k4" 3) "k2" 4) "k6" 5) "k1" 6) "k3" ---------------------------LPOP--RPOP-------------------------- 127.0.0.1:6379> LPOP mylist # 左侧(头部)弹出 "k5" 127.0.0.1:6379> RPOP mylist # 右侧(尾部)弹出 "k3" ---------------------------RPOPLPUSH-------------------------- 127.0.0.1:6379> LRANGE mylist 0 -1 1) "k4" 2) "k2" 3) "k6" 4) "k1" 127.0.0.1:6379> RPOPLPUSH mylist newlist # 将mylist的最后一个值(k1)弹出,加入到newlist的头部 "k1" 127.0.0.1:6379> LRANGE newlist 0 -1 1) "k1" 127.0.0.1:6379> LRANGE mylist 0 -1 1) "k4" 2) "k2" 3) "k6" ---------------------------LTRIM-------------------------- 127.0.0.1:6379> LTRIM mylist 0 1 # 截取mylist中的 0~1部分 OK 127.0.0.1:6379> LRANGE mylist 0 -1 1) "k4" 2) "k2" # 初始 mylist: k2,k2,k2,k2,k2,k2,k4,k2,k2,k2,k2 ---------------------------LREM-------------------------- 127.0.0.1:6379> LREM mylist 3 k2 # 从头部开始搜索 至多删除3个 k2 (integer) 3 # 删除后:mylist: k2,k2,k2,k4,k2,k2,k2,k2 127.0.0.1:6379> LREM mylist -2 k2 #从尾部开始搜索 至多删除2个 k2 (integer) 2 # 删除后:mylist: k2,k2,k2,k4,k2,k2 ---------------------------BLPOP--BRPOP-------------------------- mylist: k2,k2,k2,k4,k2,k2 newlist: k1 127.0.0.1:6379> BLPOP newlist mylist 30 # 从newlist中弹出第一个值,mylist作为候选 1) "newlist" # 弹出 2) "k1" 127.0.0.1:6379> BLPOP newlist mylist 30 1) "mylist" # 由于newlist空了 从mylist中弹出 2) "k2" 127.0.0.1:6379> BLPOP newlist 30 (30.10s) # 超时了 127.0.0.1:6379> BLPOP newlist 30 # 我们连接另一个客户端向newlist中push了test, 阻塞被解决。 1) "newlist" 2) "test" (12.54s)
Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis 中 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
---------------SADD--SCARD--SMEMBERS--SISMEMBER-------------------- 127.0.0.1:6379> SADD myset m1 m2 m3 m4 # 向myset中增加成员 m1~m4 (integer) 4 127.0.0.1:6379> SCARD myset # 获取集合的成员数目 (integer) 4 127.0.0.1:6379> smembers myset # 获取集合中所有成员 1) "m4" 2) "m3" 3) "m2" 4) "m1" 127.0.0.1:6379> SISMEMBER myset m5 # 查询m5是否是myset的成员 (integer) 0 # 不是,返回0 127.0.0.1:6379> SISMEMBER myset m2 (integer) 1 # 是,返回1 127.0.0.1:6379> SISMEMBER myset m3 (integer) 1 ---------------------SRANDMEMBER--SPOP---------------------------------- 127.0.0.1:6379> SRANDMEMBER myset 3 # 随机返回3个成员 1) "m2" 2) "m3" 3) "m4" 127.0.0.1:6379> SRANDMEMBER myset # 随机返回1个成员 "m3" 127.0.0.1:6379> SPOP myset 2 # 随机移除并返回2个成员 1) "m1" 2) "m4" # 将set还原到{m1,m2,m3,m4} ---------------------SMOVE--SREM---------------------------------------- 127.0.0.1:6379> SMOVE myset newset m3 # 将myset中m3成员移动到newset集合 (integer) 1 127.0.0.1:6379> SMEMBERS myset 1) "m4" 2) "m2" 3) "m1" 127.0.0.1:6379> SMEMBERS newset 1) "m3" 127.0.0.1:6379> SREM newset m3 # 从newset中移除m3元素 (integer) 1 127.0.0.1:6379> SMEMBERS newset (empty list or set) # 下面开始是多集合操作,多集合操作中若只有一个参数默认和自身进行运算 # setx=>{m1,m2,m4,m6}, sety=>{m2,m5,m6}, setz=>{m1,m3,m6} -----------------------------SDIFF------------------------------------ 127.0.0.1:6379> SDIFF setx sety setz # 等价于setx-sety-setz 1) "m4" 127.0.0.1:6379> SDIFF setx sety # setx - sety 1) "m4" 2) "m1" 127.0.0.1:6379> SDIFF sety setx # sety - setx 1) "m5" -------------------------SINTER--------------------------------------- # 共同关注(交集) 127.0.0.1:6379> SINTER setx sety setz # 求 setx、sety、setx的交集 1) "m6" 127.0.0.1:6379> SINTER setx sety # 求setx sety的交集 1) "m2" 2) "m6" -------------------------SUNION--------------------------------------- 127.0.0.1:6379> SUNION setx sety setz # setx sety setz的并集 1) "m4" 2) "m6" 3) "m3" 4) "m2" 5) "m1" 6) "m5" 127.0.0.1:6379> SUNION setx sety # setx sety 并集 1) "m4" 2) "m6" 3) "m2" 4) "m1" 5) "m5"
Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。
Set就是一种简化的Hash,只变动key,而value使用默认值填充。可以将一个Hash表作为一个对象进行存储,表中存放对象的信息。
------------------------HSET--HMSET--HSETNX---------------- 127.0.0.1:6379> HSET studentx name sakura # 将studentx哈希表作为一个对象,设置name为sakura (integer) 1 127.0.0.1:6379> HSET studentx name gyc # 重复设置field进行覆盖,并返回0 (integer) 0 127.0.0.1:6379> HSET studentx age 20 # 设置studentx的age为20 (integer) 1 127.0.0.1:6379> HMSET studentx sex 1 tel 15623667886 # 设置sex为1,tel为15623667886 OK 127.0.0.1:6379> HSETNX studentx name gyc # HSETNX 设置已存在的field (integer) 0 # 失败 127.0.0.1:6379> HSETNX studentx email 12345@qq.com (integer) 1 # 成功 ----------------------HEXISTS-------------------------------- 127.0.0.1:6379> HEXISTS studentx name # name字段在studentx中是否存在 (integer) 1 # 存在 127.0.0.1:6379> HEXISTS studentx addr (integer) 0 # 不存在 -------------------HGET--HMGET--HGETALL----------- 127.0.0.1:6379> HGET studentx name # 获取studentx中name字段的value "gyc" 127.0.0.1:6379> HMGET studentx name age tel # 获取studentx中name、age、tel字段的value 1) "gyc" 2) "20" 3) "15623667886" 127.0.0.1:6379> HGETALL studentx # 获取studentx中所有的field及其value 1) "name" 2) "gyc" 3) "age" 4) "20" 5) "sex" 6) "1" 7) "tel" 8) "15623667886" 9) "email" 10) "12345@qq.com" --------------------HKEYS--HLEN--HVALS-------------- 127.0.0.1:6379> HKEYS studentx # 查看studentx中所有的field 1) "name" 2) "age" 3) "sex" 4) "tel" 5) "email" 127.0.0.1:6379> HLEN studentx # 查看studentx中的字段数量 (integer) 5 127.0.0.1:6379> HVALS studentx # 查看studentx中所有的value 1) "gyc" 2) "20" 3) "1" 4) "15623667886" 5) "12345@qq.com" -------------------------HDEL-------------------------- 127.0.0.1:6379> HDEL studentx sex tel # 删除studentx 中的sex、tel字段 (integer) 2 127.0.0.1:6379> HKEYS studentx 1) "name" 2) "age" 3) "email" -------------HINCRBY--HINCRBYFLOAT------------------------ 127.0.0.1:6379> HINCRBY studentx age 1 # studentx的age字段数值+1 (integer) 21 127.0.0.1:6379> HINCRBY studentx name 1 # 非整数字型字段不可用 (error) ERR hash value is not an integer 127.0.0.1:6379> HINCRBYFLOAT studentx weight 0.6 # weight字段增加0.6 "90.8"
---------还有不少类型,不写了,我就是那90%程序员,暂时就用String
Redis的单条命令是保证原子性的,但是redis事务不能保证原子性
原子性是什么? 要么同时成功,要么同时失败
Redis事务本质:一组命令的集合。
----------------- 队列 set set set 执行 -------------------
事务中每条命令都会被序列化,执行过程中按顺序执行,不允许其他命令进行干扰。
multi
)exec
)所以事务中的命令在加入时都没有被执行,直到提交时才会开始执行(Exec)一次性完成。
discurd
)
使用watch key
监控指定数据,相当于乐观锁加锁。
使用Java来操作Redis,Jedis是Redis官方推荐使用的Java连接redis的客户端。
1.导入依赖
<!--导入jredis的包--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.2.0</version> </dependency> <!--fastjson--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.70</version> </dependency>
2.编码测试