redis
-
关于redis的要点
- redis是以key-value形式存储的非关系型数据库,直接在内存中操作数据
- 它的定位是缓存,存储临时数据,提高数据的读写速度,减轻数据库的压力
- 它是单线程操作的,所以不存在高并发访问问题
-
redis常用命令
- key不能重复,是唯一的,如果存入相同的key会覆盖前面存入的key
- value存储String类型,
Map<String, String>
# 存入key-value数据 set key value # 根据key取出value get key # 将value值递增1,如果没有该key,会创建并设置value为1 incr key # 将value值递减1,如果没有该key,会创建并设置value为-1 decr key # 删除key del key # 存入key-value,timeout是存活时间(s) setex key timeout value # 查询指定key的存活时间 ttl key # 添加数据之前判断key是否已存在,存在则添加 setnx key value
- value存储Hash类型,
Map<String, Map>
# 存入key-(hkey - hvalue)数据 hset key hkey hvalue # 根据key和hkey取出hvalue hget key hkey # 判断hash对象中hkey是否存在 hexists key hkey # 根据hkey删除一个hkey-hvalue hdel key hkey # 列出所有hkey-hvalue值 hgetall key # 列出所有hkey hkeys key # 列出所有hvalue hvals key
- value存储List类型,
Map<String, List>
,存储的元素是有序的,可重复# 从左边存入集合数据,key后面是存入的多个值 lpush key value1 value2 value3... # 从右边存入集合数据,key后面是存入的多个值 rpush key value1 value2 value3... # 从左到右列出指定索引段的List值,含头含尾,如果是列出全部值,则 lrange key 0 -1 lrange key start stop # 移除List集合最左边的值,比如[1,2,3,4],移除1 lpop key # 移除List集合最右边的值,比如[1,2,3,4],移除4 rpop key # 获取List集合的元素个数 llen key
- value存储Set集合类型,
Map<String, Set>
,存储的元素是无序的,能对Set进行并集、交集、差集操作# 存入Set集合,key后面是存入的多个值 sadd key value1 value2 value3... # 列出Set集合中所有元素 smembers key # 删除指定的Set元素 srem key value # 随机删除Set元素,count是随机删除的元素的个数 spop key count # 列出key2中没有的元素,key1和key2的差集 sdiff key1 key2 # 列出key1和key2的Set集合中共有的元素,交集 sinter key1 key2 # 列出所有key1和key2的Ser集合中元素,并集 sunion key key2 # 获取Set集合中元素个数 scard key
- value存储ZSet集合和score,能根据score将ZSet值排序,升序或倒序
# 存入Set集合和score,score value 能有多个 zadd key score1 value1 score2 value2... # 按照分数升序列出value,含头含尾,如果是列出全部值,zrange key 0 -1 zrange key start stop # 按照分数降序列出value,含头含尾,如果是列出全部值,zrange key 0 -1 zrevrange key start stop # 升序后返回指定value的排名,从0开始 zranke key value # 降序后返回指定value的排名,从0开始 zrevranke key value # 将指定value的分数递增score分 zincrby key score value # 获取Set集合中元素个数 zcard key
-
key的设计
- 唯一性:key是唯一的
- 可读性:key的名称要有意义,达到见名知意的效果
- 灵活性:key的名称不要太长,易操作
- 时效性:有些key需要给定存活时间,以防长期不用导致内存积满,比如登录用户的Session信息
-
redis的全局命令
- 列出当前数据库中所有符合条件的key,可以模糊查询
# 查询所有的key keys * # 查询以a开头的key keys a* # 查询以d结尾的key keys *d
- 判断指定key是否存在,存在返回1,不存在返回0
exists key
- 给key设置存活时间,单位s
# 与setex的区别,该命令是后期给key设置时间,不会覆盖key的数据,而后期给key设置时间使用setex命令,会覆盖key expire key seconds
- 取消给key设置的存活时间
persist key
- 查看key存储值的数据类型
type key
- 列出当前数据库中所有符合条件的key,可以模糊查询
-
redis事务
- 使用事务,先执行multi命令,然后执行操作数据命令,最后执行exec命令,取消事务使用discard命令
- redis是不支持真正的事务的,这里说的事务只是将操作数据的命令统一执行,中间有命令出错并不会让数据回滚,而是命令继续执行
-
redis持久化策略
- redis的定位是缓存,数据只存在内存中,只存储临时数据,因为数据易丢失,所以需要隔一段时间将redis中数据保存到硬盘中,而由于与硬盘交互过程相对于内存较慢,所以需要采取折中的方式达到数据访问速度与数据安全的平衡
- RDB策略,也称快照策略
- redis将某一时间点的数据全部打包生成一个.rdb的文件,保存在磁盘中,当我们重启redis服务的时候,将会读取该rdb文件恢复数据库中的数据
- 在redis安装根目录下打开
redis.windows.conf
文件,在194行找到下列代码,默认使用RDB策略,可以更改配置# 距离上一次执行rdb快照时间超过900秒,并且至少有1个键发生了改变,便会触发备份操作 save 900 1 # 距离上一次执行rdb快照时间超过300秒,并且至少有10个键发生了改变,便会触发备份操作 save 300 10 # 距离上一次执行rdb快照时间超过60秒,并且至少有1000个键发生了改变,便会触发备份操作 save 60 10000
- AOF策略,命令日志策略
- redis会将被执行的写命令添加到aof文件的末尾,该文件被保留在磁盘中。当重启redis服务的时候会优先(相对于rdb文件而言)读取aof文件,完成对redis数据的恢复
- 在redis安装根目录下打开
redis.windows.conf
文件,在581行找到找到appendonly no
,将no改成yes即可使用此策略,在609行更改策略配置 - appendonly,该选项决定了是否开启aof持久化策略
配置名称 配置选项 解释说明 appendonly yes / no 决定是否开启aof策略,默认情况下是no - appendfsync, 该选项决定了写入aof文件的频率
配置名称 配置选项 解释说明 appendfsync always 每一个redis写命令时都会被写入到aof文件中,这样会严重降低redis的速度 appendfsync everysec 每秒钟执行一次同步,将这一秒钟之内接受到的命令写入aof文件中 appendfsync no 并不是不进行aof持久化,而是让操作系统决定什么时候将命令写入aof文件中,这样我们丢失的数据将不可控
-
redis内存淘汰机制及过期Key处理
- redis内存淘汰机制
- 指当内存使用达到上限(可通过maxmemory配置,0为不限制,即服务器内存上限),根据一定的算法来决定淘汰掉哪些数据,以保证新数据的存入
- 在redis安装根目录下打开
redis.windows.conf
文件,在525行找到maxmemory <bytes>
,更改redis内存上限大小 - LRU:LRU是Least recently used,最近最少使用的意思,简单的理解就是从数据库中删除最近最少访问的数据,该算法认为,你长期不用的数据,那么被再次访问的概率也就很小了,淘汰的数据为最长时间没有被使用,仅与时间相关
- LFU:LFU是Least Frequently Used,最不经常使用的意思,简单的理解就是淘汰一段时间内,使用次数最少的数据,这个与频次和时间相关
- TTL:Redis中,有的数据是设置了过期时间的,而设置了过期时间的这部分数据,就是该算法要解决的对象。如果你快过期了,不好意思,我内存现在不够了,反正你也要退休了,提前送你一程,把你干掉吧
- 随机淘汰:生死有命,富贵在天,是否被干掉,全凭天意了
- 通过maxmemroy-policy可以配置具体的淘汰机制,系统默认的淘汰机制是no-enviction,什么都不干,报错,告诉你内存不足,这样的好处是可以保证数据不丢失
- 在redis安装根目录下打开
redis.windows.conf
文件,在548行找到maxmemory-policy noeviction
,更改maxmemroy-policy
配置
- redis过期Key处理
- 给key设置存活时间,当时间到了之后,redis清除key的策略
- 惰性删除:当访问Key时,才去判断它是否过期,如果过期,直接干掉。这种方式对CPU很友好,但是一个key如果长期不用,一直存在内存里,会造成内存浪费
- 定时删除:设置键的过期时间的同时,创建一个定时器,当到达过期时间点,立即执行对Key的删除操作,这种方式最不友好
- 定期删除:隔一段时间,对数据进行一次检查,删除里面的过期Key,至于要删除多少过期Key,检查多少数据,则由算法决定。例如:Redis每秒随机取100个数据进行过期检查,删除检查数据中所有已经过期的Key,如果过期的Key占比大于总数的25%,也就是超过25个,再重复上述检查操作
- Redis服务器实际使用的是惰性删除和定期删除两种策略:通过配合使用这两种删除策略,可以很好地在合理使用CPU和避免浪费内存之间取得平衡
- redis内存淘汰机制
-
使用Jedis工具包操作Redis,非SpringBoot项目
- 添加Jedis依赖
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
- 代码编写
@Test public void testString(){ //创建Jedis连接池,配置连接地址及端口号 JedisPool jedisPool = new JedisPool("localhost", 6379); //获取Jedis连接对象 Jedis jedis = jedisPool.getResource(); //配置连接redis的密码,默认没有密码,如果在配置文件中配置了密码,需要在此配置 //jedis.auth("root"); //使用Jedis连接对象操作Jedis数据库,这里的方法名与redis命令一样 //获取当前数据库中所有的key Set<String> keys = jedis.keys("*"); keys.forEach(System.out::println); //获取key为student存储值的类型 String type = jedis.type("student"); System.out.println("type = " + type);//zset //清空当前数据库中所有数据 String s = jedis.flushDB(); System.out.println(s);//OK }
- 添加Jedis依赖
-
使用Lettus工具包操作Redis,SpringBoot项目
- 添加Lettus依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
- 代码编写
@Autowired private StringRedisTemplate template; @Test public void testString(){ ValueOperations<String, String> stringTem = template.opsForValue(); //清除当前数据库所有key-value template.delete(template.keys("*")); // 存入key-value数据 stringTem.set("user", "禹王穆"); stringTem.set("age", "18"); // 根据key取出value System.out.println("stringTem.get(\"user\") = " + stringTem.get("user")); String user = stringTem.get("user", 0, -1); System.out.println("user = " + user); // 将value值递增1,如果没有该key,会创建并设置value为1 System.out.println("stringTem.increment(\"age\") = " + stringTem.increment("age")); // 将value值递减1,如果没有该key,会创建并设置value为-1 System.out.println("stringTem.decrement(\"age\") = " + stringTem.decrement("age")); // 删除key Boolean delete = template.delete("age"); System.out.println("delete = " + delete); // 存入key-value,timeout是存活时间(s) stringTem.set("a","1", Duration.ofSeconds(100L)); // 查询指定key的存活时间 System.out.println("template.getExpire(\"a\") = " + template.getExpire("a")); // 添加数据之前判断key是否已存在,存在则添加 Boolean absent = stringTem.setIfAbsent("b", "3"); System.out.println("absent = " + absent); }
- 添加Lettus依赖