首先区分StringRedisTemplate和RedisTemplate
1. StringRedisTemplate是继承于RedisTemplate的
2. 当你的redis数据库里面本来存的是字符串数据或者你要存取的数据就是字符串类型数据的时候,那么你就使用StringRedisTemplate即可;但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象,那么使用RedisTemplate是更好的选择。
3.
StringRedisTemplate的使用
springboot中使用注解@Autowired 即可
@Autowired
public StringRedisTemplate stringRedisTemplate;
4.
RedisTemplate中定义了5种数据结构操作
redisTemplate.opsForValue(); //操作字符串
redisTemplate.opsForHash(); //操作hash
redisTemplate.opsForList(); //操作list
redisTemplate.opsForSet(); //操作set
redisTemplate.opsForZSet(); //操作有序set
5.
StringRedisTemplate常用操作
stringRedisTemplate.opsForValue().set(key,value);//向redis里存入数据
stringRedisTemplate.opsForSet().isMember("red_123", "1")//根据key查看集合中是否存在指定数据
stringRedisTemplate.opsForValue().get("test")//根据key获取缓存中的val
stringRedisTemplate.delete("test");//根据key删除缓存
stringRedisTemplate.hasKey("546545");//检查key是否存在,返回boolean值
stringRedisTemplate.opsForSet().add("red_123", "1","2","3");//向指定key中存放set集合
stringRedisTemplate.boundValueOps("test").increment(-1);//val做-1操作
watch:监听
我们正在做一个事情,怕有人干扰;所以如果我在做一个事情,如果有人影响我了,我这个事情就全部直接失败,不要成功,因为我怕结果最后不对。
watch就是监听一个key,我要操作的时候经过这个key,别人操作也要经过这个key;那么我在监听这个key,如果有人修改了这个key里面的内容,那么我就让我做的所有事情全部失败,我担心数据被人改了,数据不安全了,可以用来做分布式锁的一部分
watch item100 监听这个100的商品
然后我要开始做事务了
set a a
set b b
set c c
然后这期间没有任何人修改,我提交事务,我就成功了
然后另一种情况
watch item100
set d d
set e e
此时另一个线程也来操作
set item100 a
修改了item
然后我提交事务的时候,会全部失败
Redis持久化机制
redis中的数据是在内存中放置的,但是为了保证数据的安全,会把数据持久化到磁盘上,这样你重启完redis后数据还会在,不然一重启就没有了
持久化机制的方式:
RDB(Redis DataBase)这是默认持久化方式
要点 | 说明 |
文件类型 | 二进制的文件,存储快,易传输 |
持久化时机 | save 900 1,在900s内有一个key发生了变化,执行RDB持久化 |
save 300 10,在300s内有10个key发生了变化,执行RDB持久化 | |
save 60 10000,在60s内有1w个key发生了变化,执行RDB持久化 | |
缺点 | RDB无法保证数据的绝对安全 |
AOF(Appendonly File)
要点 | 说明 |
文件类型 | 文本文件,相对RDB更安全;推荐同时开启AOF和RDB |
持久化机制 | appendfsync always,每执行一个写操作,立即持久化到AOF文件中 |
appendfsync everysec,每秒执行一次持久化 | |
appendfsync no,根据系统和环境,一定时间内执行一次持久化 | |
缺点 | 后期文件较大,传输困难 |
SSM整合redis
首先查询数据库,如果有数据,则返回给用户,如果没有数据,就查询数据库,然后把数据保存到redis中一份
1.先在xml中搞个对象
<bean class="redis.clients.jedis.JedisPoolConfig" id="jedisPoolConfig">
<property name="maxIdle" value="100" />
<property name="maxTotal" value="512" />
<property name="minIdle" value="10" />
<property name="maxWaitMillis" value="5000" />
</bean>
<bean class="redis.clients.jedis.JedisPool" id="jedisPool">
<constructor-arg name="PoolConfig" ref="jedisPoolConfig" />
<constructor-arg name="host" value="你的localhost" />
<constructor-arg name="port" value="你的端口" />
<constructor-arg name="timeout" value="5000" />
<constructor-arg name="password" value="你的密码" />
</bean>
然后注入一下就可以了
2.查询redis
Jedis jedis = jedisPool.getResource(); //创建连接对象
3.问题:对象应该用什么数据放到缓存中?因为数据第一次查的话肯定不会在缓存中
答:用json
/*
先查询,jedis.get(key)如果有数据,就返回给用户
如果没有就去数据库中查询,把查询的结果转换成json保存到缓存
*/
public MemberBorrowInfo getMemberById(long id) throws Exception(){
MemberBorrowInfo borrowInfo = null;
Jedis jedis = jedisPool.getResource(); //缓存连接池
String infoJson = jedis.get("borrowInfo:" + id); //查询缓存
if(infoJson == null){ //如果缓存中没有就查询数据库
System.err.println("查询数据库");
borrowInfo = borrowInfoMapper.getMemberById(id); //
String borrowinfoJson = objectMapper.writeValueAsString(borrowInfo);//writeValueAsString :用来把Java对象转化为json
jedis.set("borrowinfo:" + id,borrowinfoJson);
}else{
borrowInfo = objectMapper.readValue(infoJson,MemberBorrowInfo.class); //如果有就直接返回给用户
}
jedis.close();
return borrowInfo;
}
Redis中的主从模式
为了防止我们的数据库坏掉之后数据丢失,所以需要主从模式
在主从复制中数据库分为主数据库和从数据库,从数据库一般都是只读的,并且接收从主数据库同步过来的数据;一个主可以有多个从,但是一个从只能有一个主,从数据库故障不影响其他从的读和主的读和写;主数据库的故障不影响从的读,但是redis不再提供写服务,因为怕数据出现错乱
配置:
只需要启动多个redis
在从系的redis里写上
replicaof 主ip 主redis端口
哨兵
哨兵建立在主从模式的基础上
哨兵可以解决主从架构中的单点故障问题
当主宕机之后,哨兵会去从里选一个新的主
原来的主恢复后会变成从
多个哨兵形成集群,互相监控
每个redis里都会有一个哨兵
Redis集群
集群是主从+哨兵的模式
集群是无中心的
集群是投票机制,节点数量必须是奇数
集群节点默认分配16384个哈希槽
为了保证安全,每个节点至少有一个从节点
Redis中有哪几种数据类型,说一下分别应用的场景?
主要有以下这几种数据类型:
String
hash
lsit
set
sorted set
String:
这是最简单的数据类型,就是普通的set和get,做简单的KV缓存
hash:
这个是类似map的一种结构,一般可以将结构化的数据,比如一个对象缓存在redis里,然后每次读写缓存的时候,可以操作hashll里的某个字段
hset person name bingo
hset person age 20
hset person id 1
hget person name
person = {
"name": "bingo",
"age": 20,
"id": 1
}
list:
list是有序列表,list可以存储一些列表型的数据结构,类似粉丝列表、文章的评论列表之类的东西。
还可以通过lrange,读取某个闭区间内的元素,可以基于list实现分页擦汗寻;基于redis实现简单的高性能分页,可以做类似微博那种下拉不断分页的东西,性能高,就一页一页走;
还可以搞一个简单的消息队列,从list头插进去,从尾巴那里弄出来。
lpush mylist 1
lpush mylist 2
lpush mylist 3 4 5
# 1
rpop mylist
set:
set是无序集合,自动去重;
还可以基于set搞一个交集、并集、差集的操作,可以把微博上的两个人的粉丝列表整一个交集,看看他俩有什么共同好友;
# 求两set的交集
sinter yourSet mySet
# 求两set的并集
sunion yourSet mySet
sorted set:
sorted set 是排序的 set,去重但可以排序,写进去的时候给一个分数,自动根据分数排序。
先设置三个分数
zadd board 85 zhangsan
zadd board 72 lisi
zadd board 63 zhaoliu
# 获取排名前三的用户(默认是升序,所以需要 rev 改为降序)
zrevrange board 0 3
# 获取某用户的排名
zrank board zhaoliu
Redis的过期策略和淘汰机制
Redis的过期策略是:
定期删除和惰性删除
定期删除就是:redis默认每隔100ms就会【随机】抽取一些【已经设置了过期时间的key】,检查其是否过期,如果过期了,就删除
惰性删除:在你使用到某个key的时候,redis会先检查一下,这个key是否设置了过期时间以及是否过期了?如果过期了此时就会删除,不会给你返回任何东西。
问题:
如果定期删除漏掉了一些key,而你也没有去获取这些key,那么惰性删除也不会执行,那么redis的内存会越来越高,导致redis内存快耗尽了,咋办?
答案:
采用内存淘汰机制
redis的内存淘汰机制有以下几个:
noeviction:当内存不足时,新的写入操作会报错,一般没人用
allkeys-lru:当内存不足的时候,在所有的key中,挑选最近最少用的key删除
allkeys-random:当内存不足的时候,在所有的key中,随机删除key;
volatile-lru:在已经设置了过期时间的key中,删除最近最少使用的key
volatile-random:在已经设置了过期时间的key中,随机删除key
volatile-ttl:在已经设置了过期时间的key中,删除将要过期的key