目录
1.Redis(远程字典服务)
- 什么是redis,redis是一个典型的非关系型数据库,且由于它的特殊的数据结构,也可以当做消息中间件。redis的数据结构一般有5个基本数据类型(单纯String,List,set,Hash,Zset),3个特殊的数据类型。
- redis是一个缓存数据库,由于它是基于内存内存中,所以效率很高,且支持持久化,就是把数据存到硬盘上。
- redis是单线程的
最好先学习redis的几大数据类型这样可以快速上手
2.Redis数据类型
基础很重要!!!数据类型很重要!!!
2.1 String
#字符串
set key value
#在value后追加字符串
append key value
#字符串截取 range
range key begin,e
#替换字符串中的指定位置 就是把字符串的某个字符替换
SETRANGE jmj 2 hh
#用SETNX创建key,如果当前已存在该key,则不会执行 ,相当于 if not exit, then set
SETNX
#setex 相当于设置EXPIRE 创建的时候设置修改时间,如果key已存在,那么会覆盖过期时间
SETEX key second value
#msetnx 只要有一个key已经存在,MSETNX一个操作都不会执行。 由于这种特性,MSETNX可以实现要么所有的操作都成功,要么一个都不执行,这样可以用来设置不同的key,来表示一个唯一的对象的不同字段。MSETNX是原子的,所以所有给定的keys是一次性set的
msetnx key value key value key value ....
#getset 如果当前不存在key,返回空后,创建key,设置value
127.0.0.1:6339[2]> getset db aaa
(nil)
127.0.0.1:6339[2]> keys *
1) "k3"
2) "user:1:name"
3) "k1"
4) "k2"
5) "db"
6) "user:1:age"
127.0.0.1:6339[2]> get db
"aaa"
2.2 List
#不存在则创建list并从list的左边添加元素
LPUSH list element
#获取list中的元素
LRANGE list1 start stop
#获取list1中的全部元素
LRANGE list1 0 -1
#不存在则创建list并从list的右边添加元素
RPUSH list element
#移除元素
#移除lsit左边第一个元素
LPOP key
#移除lsit右边第一个元素
RPOP key
#获取一个list的长度
LLEN key
#移除list中的指定数量的指定元素 count为移除多少个,从上到下开始
LREM key count value
#RPOPLPUSH 移除list中最右边的元素,并把这个元素移动到新的list中
127.0.0.1:6339[2]> RPUSH list1 h1 h2 h3
(integer) 3
127.0.0.1:6339[2]> RPOPLPUSH list1 list2
"h3"
127.0.0.1:6339[2]> LRANGE list2 0 -1
1) "h3"
127.0.0.1:6339[2]> LRANGE list1 0 -1
1) "h1"
2) "h2"
#判断是否存在列表
EXISTS list
#lset将列表中指定下标的值进行替换,相当于更新操作。如果key不存在,会报错,如果key存在,但是下表不存在,则报错
lset key index value
#在list指定元素的前面或者后面添加一个元素,只会在第一个匹配的元素位置插入,
LINSERT key before/after 指定元素 插入元素
2.3 Set
#set中的值不能重复 sadd key element
127.0.0.1:6339> sadd myset1 hello
(integer) 1
127.0.0.1:6339> sadd myset1 world
(integer) 1
127.0.0.1:6339> sadd myset1 world
(integer) 0
#SMEMBERS 查看set中的所有元素
127.0.0.1:6339> SMEMBERS myset1
1) "world"
2) "hello"
127.0.0.1:6339>
#SISMEMBER判断元素是否在set集合中 存在则返回1 ,不存在则返回0
127.0.0.1:6339> SMEMBERS myset1
1) "world"
2) "hello"
127.0.0.1:6339> SISMEMBER myset1 h
(integer) 0
127.0.0.1:6339> SISMEMBER myset1 world
(integer) 1
127.0.0.1:6339>
#随机获取set中的某个元素
127.0.0.1:6339> SRANDMEMBER myset1
"world"
127.0.0.1:6339> SRANDMEMBER myset1
"world"
127.0.0.1:6339> SRANDMEMBER myset1
"hello"
127.0.0.1:6339> SRANDMEMBER myset1
#随机移除set中的某个元素 如果count 默认值是1
SPOP key count
#交集 SINTER获取交集,
127.0.0.1:6339[2]> sadd set1 h1 h2 h3 h4
(integer) 4
127.0.0.1:6339[2]> sadd set2 h1 h2 h3 h4 h5
(integer) 5
127.0.0.1:6339[2]> SINTER set1 set2
1) "h2"
2) "h1"
3) "h4"
4) "h3"
127.0.0.1:6339[2]>
#SDIFF获取 set2中在set1没有的元素
SDIFF获取c set2 set1
127.0.0.1:6339[2]> SDIFF set1 set2
(empty array)
127.0.0.1:6339[2]> SDIFF set2 set1
1) "h5"
127.0.0.1:6339[2]>
#并集SUNION 获取set1和set2的并集
SUNION set1 set2
2.4 Hash
这个数据结构是 key -map,相当于把value换成了map集合
#hset hget赋值和查看语句
127.0.0.1:6339[2]> hmset hset f1 111 f2 222
OK
#查看一个field值
127.0.0.1:6339[2]> HGET hset f1
"111"
127.0.0.1:6339[2]>
#查看所有的field值
127.0.0.1:6339[2]> HGETALL hset
1) "f1"
2) "111"
3) "f2"
4) "222"
#删除某一个field
HDEL hset f1
127.0.0.1:6339[2]> HDEL hset f1
(integer) 1
127.0.0.1:6339[2]> HGETALL hset
1) "f2"
2) "222"
127.0.0.1:6339[2]>
#HKEYS 获取所有的field ,HVALS 获取所有的value
127.0.0.1:6339[2]> HKEYS hset
1) "f2"
127.0.0.1:6339[2]> HVALS hset
1) "222"
127.0.0.1:6339[2]>
2.5 Zset
zset就是排了序的SET集合,因为zset中的每个成员有一个分数(score)。
#zset是有序集合,相当于排好序的set集合,根据分数score来进行排序 zadd key score value,默认从低到高排序
127.0.0.1:6339[2]> ZADD user 1 xiaoming
(integer) 1
127.0.0.1:6339[2]> ZADD user 2 xiaowang
(integer) 1
127.0.0.1:6339[2]> ZRANGE user 0 -1
1) "xiaoming"
2) "xiaowang"
127.0.0.1:6339[2]> ZRANGE user 0 -1 withscores
1) "xiaoming"
2) "1"
3) "xiaowang"
4) "2"
127.0.0.1:6339[2]>
#查看一个分数区间中的所有元素 ZRANGEBYSCORE key -inf inf withscores
#-inf 表示最小,inf表示最大 withscore表示显示的时候附加分数
127.0.0.1:6339[2]> ZRANGEBYSCORE user -inf inf
1) "xiaoli"
2) "xiaoming"
3) "xiaowang"
127.0.0.1:6339[2]> ZRANGEBYSCORE user -inf inf withscores
1) "xiaoli"
2) "0.5"
3) "xiaoming"
4) "1"
5) "xiaowang"
6) "2"
127.0.0.1:6339[2]>
#zrem 移除zset中的指定元素
127.0.0.1:6339[2]> ZREM user xiaoli
(integer) 1
127.0.0.1:6339[2]> ZRANGEBYSCORE user -inf inf
1) "xiaoming"
2) "xiaowang"
127.0.0.1:6339[2]>
#ZREVRANGE 从大到小排序 ,在springboot的jedis中没有withscores这个参数
127.0.0.1:6339[2]> ZRANGEBYSCORE user -inf inf withscores
1) "xiaoming"
2) "1"
3) "xiaowang"
4) "2"
127.0.0.1:6339[2]> ZREVRANGE user 0 -1 withscores
1) "xiaowang"
2) "2"
3) "xiaoming"
4) "1"
127.0.0.1:6339[2]>
#zcount 判断分数在这个区间的元素有几个
ZCOUNT user 0.5 1
#zcard获zset中的成员个数
zcard key
3.Redis事务
redis中是有事务的,说到事务顺便解释一下锁,一般有乐观锁和悲观锁,悲观锁就是认为任何情况下都需要加锁,而乐观锁就是只有在修改提交的操作才会加锁,他会比较version版本号,如果发生变化就会失败,但是乐观锁不能解决脏读。
redis中的事务就是一组命令的集合,可以理解为把一条条命令依次放到一个队列中。
单条命令是原子性的,但是整个事务并不是原子性,而且不支持回滚。因此redis中事务不支持ACID。
值得一提的是,redis事务中的命令如果是编译型异常,那么整个事务的所有命令都会执行失败。如果是事务中的某条命令的运行时异常,则只会单条失败,其余的成功。
#MULTI开启事务,EXEC执行 ,放弃事务DISCARD
127.0.0.1:6339> MULTI
OK
127.0.0.1:6339> LPUSH ll xiaowang xiaoming
QUEUED
127.0.0.1:6339> LPUSH ll xiaoli
QUEUED
127.0.0.1:6339> LRANGE ll 0 -1
QUEUED
127.0.0.1:6339> LPOP ll
QUEUED
127.0.0.1:6339> LRANGE ll 0 -1
QUEUED
127.0.0.1:6339> EXEC
1) (integer) 2
2) (integer) 3
3) 1) "xiaoli"
2) "xiaoming"
3) "xiaowang"
4) "xiaoli"
5) 1) "xiaoming"
2) "xiaowang"
127.0.0.1:6339>
#列表l1下EXISTS l1之后执行,所以第一个exists返回0
127.0.0.1:6339> MULTI
OK
127.0.0.1:6339> LPUSH ll xx
QUEUED
127.0.0.1:6339> EXISTS l1
QUEUED
127.0.0.1:6339> LPUSH l1 xx
QUEUED
127.0.0.1:6339> EXISTS l1
QUEUED
127.0.0.1:6339> EXEC
1) (integer) 3
2) (integer) 0
3) (integer) 1
4) (integer) 1
127.0.0.1:6339>
#放弃事务DISCARD
127.0.0.1:6339> MULTI
OK
127.0.0.1:6339> set aa a
QUEUED
127.0.0.1:6339> DISCARD
OK
127.0.0.1:6339> get aa
(nil)
127.0.0.1:6339>
#运行时报错和编译报错,运行时报错只有报错的那一个命令才不会执行,编译报错会让事务的所有命令都不执行
127.0.0.1:6339> MULTI
OK
127.0.0.1:6339> set a "sb"
QUEUED
127.0.0.1:6339> INCR a
QUEUED
127.0.0.1:6339> get a
QUEUED
127.0.0.1:6339> set b 1
QUEUED
127.0.0.1:6339> get b
QUEUED
127.0.0.1:6339> EXEC
1) OK
2) (error) ERR value is not an integer or out of range
3) "sb"
4) OK
5) "1"
127.0.0.1:6339>
redis可以实现乐观锁,只需要对key加上watch,相当于一个监视器,unwatch来解除监视。
127.0.0.1:6339> set money 1000
OK
127.0.0.1:6339> watch money
OK
127.0.0.1:6339> MULTI
OK
127.0.0.1:6339> DECRBY money 100
QUEUED
127.0.0.1:6339> get money
QUEUED
127.0.0.1:6339> EXEC
1) (integer) 900
2) "900"
127.0.0.1:6339>unwatch money
#如果在EXEC ,也就是事务执行之前,有线程对这个key进行了修改,那么这个事务将会执行失败,因为此时的version已经发生了改变
#unwatch解锁
4.Redis整合Springboot
整合依赖
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
所有的命令可以通过Jedis对象来实现。比如举个例子,对String数据类型进行操作
public static void main(String[] args) {
Jedis jedis = JedisUtil.getJedis();
//清楚数据库中数据,便于观察
jedis.flushDB();
log.info("String测试");
log.info("是否存在k1 " + jedis.exists("k1"));
log.info("String新增 k1,v1 " + jedis.set("k1", "v1"));
log.info("setnx如果不存在则创建,存在不创建 k1,v2 " + jedis.setnx("k1", "v2"));
log.info("setnx如果不存在则创建,存在不创建 k2,v2 " + jedis.setnx("k2", "v2"));
log.info("k1的值" + jedis.get("k1"));
log.info("k2的值" + jedis.get("k2"));
}
运行结果
除了数据类型的基本应用,当然,还有其他各种运用,如分布式锁,日志缓存,社交网络图,秒杀等等。暂时分享这么多,谢谢观看。