Redis简介

Redis是以key-value形式存储,和传统的关系型数据库不一样.不一定遵循传统数据库的一些基本要求.(非关系型的,分布式的,开源的,水平可拓展的)

优点:

  • 对数据高并发读写(直接是内存中进行读写的)
  • 对海量数据的高效率存储和访问
  • 对数据的可拓展性和高可用性.
  • 单线程操作,每个操作都是原子操作,没有并发相关问题(redis 6)

缺点:

  • redis(ACID处理非常简单)
  • 无法做太复杂的关系数据库模型

Redis是以key-value store存储.
键可以包含:(string)字符串,(hash)哈希,(list)链表,(set)集合,(zset)有序集合.这些数据集合都指出push/pop,add/remove及取交集和并集以及更丰富的操作.redis支持各种不同方式排序,为了保证效率,数据都是缓存在内存中.它可以从周期性的把更新的数据写入到磁盘或者把修改操作写入追加的文件中.

redis定位是缓存, 提高数据读写速度, 减轻对数据库存储与访问压力

Redis的安装

Window在GitHub上搜索安装, Linux直接在官网下载即可

Redis默认端口是: 6379

安装好后会自动启动服务器,并且没有密码

若要设置密码, 可在安装目录下打开redis.windows-service.conf文件, 找到requirepass字段(大约443行), 将注释解开后可自定义密码(需要重启Redis服务)

进入到安装目录下,双击运行redis-cli.exe程序, 或者在cmd中输入redis-cli(若设置密码则输入redis-cli -a 密码)

数据类型(cmd中的命令)

String类型

String类型包含多种类型的特殊类型,并且是二进制安全的.比如序列化的对象进行存储,比如一张图片进行二进制存储.,比如一个简单的
Map<String, String> map
map.put(“name”, Json.toJsonString(user));

类型命令 key 参数数据

set key value -> 存入键值对
get key -> 根据键取出值

incr key -> 把值递增1
decr key -> 把值递减1

del key -> 根据键删除键值对

setex key timeout value -> 存入键值对,timeout表示失效时间,单位s

ttl key->可以查询出当前的key还剩余多长时间过期

setnx key value -> 如果key已经存在,不做操作, 如果key不存在,直接添加

incrby key num -> 偏移值
mset k1 v1 k2 v2 … -> 批量存入键值对
mget k1 k2 … -> 批量取出键值
append key ‘value’ -> 原值后拼接新内容
setnx key value -> 存入键值对,键存在时不存入
setex key timeout value -> 存入键值对,timeout表示失效时间,单位s
ttl ->可以查询出当前的key还剩余多长时间过期
setrange key index value -> 修改键对应的值,index表示开始的索引位置

应用情景

计数器:许多运用都会使用redis作为计数的基础工具,他可以实现快速计数、查询缓存的功能,同时数据可以异步落地到其他的数据源。
如:视频播放数系统就是使用redis作为视频播放数计数的基础组件。
incr viewnum 1
共享session:出于负载均衡的考虑,分布式服务会将用户信息的访问均衡到不同服务器上, 用户刷新一次访问可能会需要重新登录,为避免这个问题可以用redis将用户session集中管理,在这种模式下只要保证redis的高可用和扩展性的,每次获取用户更新或查询登录信息都直接从redis中集中获取。

hash类型

Hash类型是String类型的field和value的映射表.或者说是一个String集合.它特别适合存储对象,相比较而言,讲一个对象存储在Hash类型里要比存储在String类型里占用更少的内存空间,并方便存储整个对象

Map<string, Map<string, ?>> map

hset key hashkey hashvalue -> 存入一个hash对象
hget key hashkey -> 根据hash对象键取去值
hexists key hashkey -> 判断hash对象是含有某个键
hdel key hashkey -> 根据hashkey删除hash对象键值对

hincrby key hashkey 递增值 -> 递增hashkey对应的值
hlen key -> 获取hash对象键的数量
hkeys key -> 获取hash对象的所有键
hvals key -> 获取hash对象的所有值
hgetall key -> 获取hash对象的所有数据

同样有hsetnx,其作用跟用法和setnx一样

应用情景

哈希结构相对于字符串序列化缓存信息更加直观,并且在更新操作上更加便捷。
所以常常用于用户信息等管理,但是哈希类型和关系型数据库有所不同,哈希类型是稀疏的,
而关系型数据库是完全结构化的,关系型数据库可以做复杂的关系查询,而redis去模拟关系型复杂查询
开发困难,维护成本高

list类型

Redis中的List类似Java中的queue,也可以当做List来用.
List类型是一个链表结构的集合,其主要功能有push,pop,获取元素等.更详细的说,List类型是一个双端链表的结构,我们可以通过相关操作进行集合的头部或者尾部添加删除元素,list的设计非常简单精巧,即可以作为栈,又可以作为队列.满足绝大多数需求.

Map<String, List>

rpush key value -> 往列表右边添加数据
lrange key start end -> 范围显示列表数据,全显示则设置0 -1
lpush key value -> 往列表左边添加数据
lpop key -> 弹出列表最左边的数据
rpop key -> 弹出列表最右边的数据
llen key -> 获取列表长度

linsert key before/after refVal newVal -> 参考值之前/后插入数据
lset key index value -> 根据索引修改数据
lrem key count value -> 在列表中按照个数删除数据
ltrim key start end -> 范围截取列表
lindex key index -> 根据索引取列表中数据

应用场景

1.用户收藏文章列表:
xxxx_user_articles:uid [aid1, aid2, aid3…..]

set类型

Set集合是string类型的无序集合,set是通过hashtable实现的,对集合我们可以取交集,并集,差集.

sadd key value -> 往set集合中添加元素
smembers key -> 列出set集合中的元素
srem key value -> 删除set集合中的元素
spop key count -> 随机弹出集合中的元素

sdiff key1 key2 -> 返回key1中特有元素(差集)
sdiffstore var key1 key2 -> 返回key1中特有元素存入另一个set集合
sinter key1 key2 -> 返回两个set集合的交集
sinterstore var key1 key2 -> 返回两个set集合的交集存入另一个set集合
sunion key1 key2 -> 返回两个set集合的并集
sunionstore var key1 key2 -> 返回两个set集合的并集存入另一个set集合
smove key1 key2 value -> 把key1中的某元素移入key2中
scard key -> 返回set集合中元素个数
sismember key value -> 判断集合是否包含某个值
srandmember key count -> 随机获取set集合中元素

应用场景

1,去重;

2,抽奖;
1>准备一个抽奖池: sadd luckydraw 1 2 3 4 5 6 7 8 9 10 11 12 13
2>抽3个三等奖: spop luckydraw 3
3>抽2个二等奖: spop luckydraw 2
4>抽1个二等奖: spop luckydraw 1

sorted_set类型

zadd key score column -> 存入分数和名称

zincrby key score column -> 偏移名称对应的分数

zrange key start end -> 按照分数升序输出名称
zrevrange key start end -> 按照分数降序输出名称

zrank key name -> 升序返回排名
zrevrank key name -> 降序返回排名
zcard key -> 返回元素个数

zrangebyscore key min max [withscores] -> 按照分数范围升序输出名称
zrevrangebyscore key max min [withscores] -> 按照分数范围降序输出名称
zrem key name -> 删除名称和分数
zremrangebyscore key min max [withscores] -> 根据分数范围删除元素
zremrangebyrank key start end -> 根据排名删除元素
zcount key min max -> 按照分数范围统计个数

应用场景

排行榜:有序集合经典使用场景。例如视频网站需要对用户上传的视频做排行榜,榜单维护可能是多方面:
按照时间、按照播放量、按照获得的赞数等。

总结

如果确定使用redis, 此时需要考虑使用哪个数据类型 【偏redis原生数据结构】

  • 如果要排序选用zset
  • 如果数据是多个且允许重复选用list
  • 如果数据是多个且不允许重复选用set
  • 剩下的使用string
  • 如果是对象类型也可使用hash
1
2
3
4
5
6
hash  ---> 转换成json格式
{
key1:value1
key2:value2 ------> "{key1:value1, key2:value2}"
}
JSON.toJsonString(map)

有些公司约定: 所有的redis的key跟value都使用字符串(排除使用zset场景) 【偏redis String类型json结构】
1>如果要排序选用zset
2>剩下的使用string

优点: java操作中如果使用各种类型: list set 其他的 操作redis时需要明确指定的泛型, 麻烦所以有些公司统一规范, 统一使用字符串, 减少泛型操作

1
2
3
4
5
6
7
List<String>list = ...
Set<String> set = ....
Map<String, Object> map = ....

List<Object> list = redis对象.getList
Set<Object> set =redis对象.getSet
Map<Object, Object> map = redis对象.getMap

设计 key 与 value值

key的设计
1:唯一性
2:可读性
设计keyvalue 缓存用户收藏文章列表
key value
article_favor_list:uid1 [1,2,3,4]
article_favor:uid2 [1,2,3,4]
3:灵活性
4:时效性

value值
根据需求决定

redis 进阶

redis高级命令

返回满足的所有键
keys * (可以模糊查询)
exists 是否存在指定key
expire 设置某个key的过期时间.使用ttl查看剩余时间
persist 取消过期时间

flushdb 清空当前数据库,flushall清空所有数据库

select 选择数据库 数据库为0到15(一共16个数据库) 默认进入的是0数据库
move [key] [数据库下标] 讲当前数据中的key转移到其他数据库中
randomkey 随机返回数据库里的一个key
rename重命名key
echo 打印名
dbsize 查看数据库的key数量
info 获取数据库信息
config get 实时传储收到的请求(返回相关的配置信息)
config get * 返回所有配置

redis安全性

因为redis速度非常快,所以在一台比较好的服务器下,一个外部用户在一秒内可以进行15w次的密码尝试,这意味你需要设定非常强大的密码来方式暴力破解.
vi编辑redis.conf文件,找到下面进行保存修改
requirepass [密码]
重启服务器 pkill redis-server
再次进入cmd 127.0.01:6379>keys *
(error)NOAUTH Authentication required.
会发现没有权限进行查询auth [密码]
输入密码则成功进入
每次进入的时候都需要输入免密,还有种简单的方式:

redis-cli -a [密码]

redis事务[拓展]

Redis的事务非常简单,使用方法如下:
首先是使用multi方法打开事务,然后进行设置,这时设置的数据会放到队列里进行保存.最后使用exec执行.把数据依次存储到redis中.使用discard方法取消事务.

实际运用

1.Jedis基本使用

1
2
3
4
5
导入依赖:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 简单配置
@Test
public void testJedisPool() {
// 1:创建Jedis连接池
JedisPool pool = new JedisPool("localhost", 6379);
// 2:从连接池中获取Jedis对象
Jedis jedis = pool.getResource();
/* 设置密码
jedis.auth(密码); */
// 3:TODO 调用API
System.out.println(jedis);
// 4:关闭资源
jedis.close();
pool.destroy();
}
---------------------------------------------
// 自定配置
@Test
public void testTool(){
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
////最大连接数, 默认8个
config.setMaxTotal(100);
////最大空闲连接数, 默认8个
config.setMaxIdle(20);
//获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间, 默认-1
config.setMaxWaitMillis(-1);
//在获取连接的时候检查有效性, 默认false
config.setTestOnBorrow(true);
JedisPool pool = new JedisPool(config,"192.168.122.128",6379,5000,"wolfcode");
Jedis j = pool.getResource();
String name = j.get("name");
System.out.println(name);
j.close();
pool.close();
pool.destroy();
}

PS: Jedis的API和cmd基本相同

2.集成SpringBoot

1
2
3
4
5
导入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置(.yml文件)

1
2
3
4
5
spring:
redis:
host: 127.0.0.1
port: 6379
password: admin

API使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Resource
private StringRedisTemplate template;

@Test
public void testRedisTemplate() {
// 操作string
template.opsForValue().xx();
// 操作hash
template.opsForHash().xx();
// 操作list
template.opsForList().xx();
// 操作set
template.opsForSet().xx();
// 操作zset
template.opsForZSet().xx();
}
-----------------------------------------
template.opsForValue(); // 操作字符串
template.opsForHash(); // 操作hash
template.opsForList(); // 操作list
template.opsForSet(); // 操作set
template.opsForZSet(); // 操作有序set

PS: Spring中redis的API和cmd并不相同, 可以通过见名知意调用API

集成SpringBoot中的(主要)方法

StringRedisTemplate(类名) 作用
String
template.opsForValue().set(key, value) 设置key对应的value值
template.opsForValue().set(key, value, timeout, unit)) 设置当前的key以及value值并且设置过期时间
template.opsForValue().get(key) 取出key值所对应的值
template.opsForValue.increment(key) key对应的value加1
template.opsForValue.decrement(key) key对应的value减1
template.opsForValue().setIfAbsent(key, value) 存在key则不设置
template.hasKey(key) 判断是否有key
template.keys(key) 模糊查询key
template.getExpire(key) 返回当前key所对应的剩余过期时间
template.delete(key/keys) 删除单个key(或者多个keys)值
Hash
template.opsForHash().put(key, hashKey, value) 新增hashMap值
template.opsForHash().get(key, field)/template.opsForHash().values(key)获取所有 获取变量中的指定map键的值
template.opsForHash().delete(key, field) 删除key中的field值
template.opsForHash().hasKey(key, field) 判断key中的field值是否存在
List(左/右)
template.opsForList().r/lightPush(key, value) 从左/右添加key对应的value值
template.opsForList().r/lightPop(key) 从左/右移出key值
template.opsForList().size(key) 获取对应key的长度
template.opsForList().r/lange(key, start, end) 获取列表指定范围内的元素(start开始位置, 0是开始位置,end 结束位置, -1返回所有)
Set
template.opsForSet().add(key, values) 添加key的values(单个/多个)元素
template.opsForSet().remove((key, values) 移除(单个/多个)元素
template.opsForSet().pop(key) 获取集合的大小
template.opsForSet().size(key) 获取集合的大小
template.opsForSet().intersect(key, otherKeys) 获取两个集合的交集
template.opsForSet().union(key, otherKeys) 获取两个集合的并集
template.opsForSet().difference(key, otherKeys) 获取两个集合的差集
sorted_set
template.opsForZSet().add(key, value, score) 添加元素
template.opsForZSet().reverseRange(key, start, end) 返回排序结果(start开始位置, 0是开始位置,end 结束位置, -1返回所有)
template.opsForZSet().reverseRangeByScore(key, min, max) 结果从小到大排序
template.opsForZSet().incrementScore(key, value, delta) 修改元素的score值
template.opsForZSet().zCard(key) 获取集合的大小
template.opsForZSet().rank(key, value) 按照元素的score值由小到大排列
template.opsForZSet().reverseRank(key, value) 元素的score值由大到小排列
template.opsForZSet().remove(key, values) 删除对应的value,value可以为多个值