Redis简介
数据库分类
关系型数据库 MySQL 、oracle
NoSQL数据库 非关系型数据库 分类
键值存储 查找速度快 数据无结构化
列存储数据库 查找速度快、可拓展性强,容易进行分布式扩展 功能相对局限
文档型数据库 数据结构要求不严格,表结构可变,不需要预定义表结构 查询性能不高,缺乏统一的查询语法
图形数据库 利用图结构相关算法,不好做分布式的集群方案
非关系型数据库特点
1.数据模型简单
2.需要灵活性更强的应用系统
3.对数据库性能要求较高
4.不需要高度的数据一致性
5.对于给定key,比较容易映射复杂值的环境.
Redis优缺点
优点: 对数据高并发读写(直接是内存中进行读写的) 对海量数据的高效率存储和访问 对数据的可拓展性和高可用性. 单线程操作,每个操作都是原子操作,没有并发相关问题(redis 6)
缺点: redis(ACID处理非常简单) 无法做太复杂的关系数据库模型
redis定位是缓存, 提高数据读写速度, 减轻对数据库存储与访问压力
一旦涉及到缓存,首要的候选方案:Redis
数据类型
redis命令格式:
类型命令 + key + 参数数据
String类型:
Map<String, String> map
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 如果可任意已经操作 不作操作,否则直接添加
hash类型
Map<string, Map<string, ?>> map
hset key hashkey hashvalue 存入一个hash对象
hget key hashkey 根据hash对象键取值
hexists key hashkey -> 判断hash对象是含有某个键
hdel key hashkey -> 根据hashkey删除hash对象键值对
list类型
Map<String, List>
rpush key value -> 往列表右边添加数据
lrange key start end -> 范围显示列表数据,全显示则设置0 -1
lpush key value -> 往列表左边添加数据
lpop key -> 弹出列表最左边的数据
rpop key -> 弹出列表最右边的数据
llen key -> 获取列表长度
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集合中元素
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 -> 返回元素个数
类型选用
value选用
1>如果要排序选用zset
2>如果数据是多个且允许重复选用list
3>如果数据是多个且不允许重复选用set
4>如果数据是对象,选用hash,或者String
5>剩下的使用string
key设计
1.唯一性 一般使用数据的主键保证唯一
2.可读性 加上一些能描述key作用的前缀
一般前缀: 项目_模块_可读性前缀:主键
3.灵活性
4.时效性
redis进阶
redis高级命令
keys * 返回满足的所有键 (可以模糊查询)
exists 是否存在指定key
expire 设置某个key的过期时间,使用ttl查看剩余时间
persist 取消过期时间
flushdb 清空当前数据库
flushall 清空所有数据库
select 选择数据库
rename 重命名key
redis安全性
在redis.config进行密码修改
用redis-cli -a[密码]启动
redis事务
Redis事务可以—次执行多个命令,并且带有以下三个重要的保证:
1.批量操作在发送EXEC命令前被放入队列缓存。
2.收到EXEC命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
3.在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
执行事务的三个阶段
1.开始事务
2.命令入队
3.执行事务
单个Redis 命令的执行是原子性的,但Redis 没有在事务上增加任何维持原子性的机制,所以Redis事务的执行并不是原子性的。
事务可以理解为一个打包的批量执行脚本,但批是指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。
redis持久化机制
redis是一个支持持久化的内存数据库,也就是说redis经常将内存中的数据同步到硬盘保证持久化
redis持久化有两种方式
RDB方式
snapshotting快照,默认方式,将内存中以快照的方式写入到二进制文件中,默认为dump.rbd,可以自动配置设置自动做快照持久化方式,可以自定义配置
snapshotting
save 900 1 900秒内如果超过1个key被修改则发起快照保存
save 300 10 300秒捏如果超过10个jey被修改则发起快照保存
save 60 10000
AOF方式
append-only-file
redis会将一个收到的写命令都通过write函数追加到命令中,当redis重新启动是会执行文件中保存的写命令来在内存中重建这个数据库的内容,这个文件在bin目录下:appendonly.aof
aof不是立即写到硬盘中,可以通过配置文件修改强制写到硬盘中
appendonly yes //启动aof持久化方式有三种修改方式
#appendsync always收到命令就立即写到磁盘,效率最慢,但能保证完全的持久化
#appendsync everysec 每秒写入磁盘一次,在性能和持久化方面做了很好地折中
#appendsync no 完全以依赖os,性能最好,但持久化没保证
根据数据量、数据重要性选用
redis内存淘汰机制及过期key处理
内存淘汰机制
1.LRU 最近最少使用
2.LFU 最不经常使用
3.TTL 优先淘汰即将过期的数据
4.random 随机淘汰
volatile-lru/lfu/random/ttl 对以设置过期时间的数据集进行处理
allkeys-lru/lfu/random 对所有数据集处理
no-envictio 什么都不做
过期key处理
惰性删除,当访问时判断是否过期,过期再删除
定时删除:设置键的过期时间的同时,创建一个定时器,当到达过期时间点立即执行删除操作
定期删除,每隔一段时间,对数据进行一次检查,删除里面的过期key(优先选用)
实际运用
Jedis基本使用
配置依赖
创建Jedis连接池
从连接池获取对象
执行操作(redis的命令就是Jedis的方法)
关闭资源
String类型
JedisPool pool = new JedisPool("localhost",6379); Jedis jedis = pool.getResource(); jedis.set("name","jqy"); //存入键值对 jedis.set("age","18"); System.out.println(jedis.get("name")); //根据键取出值 System.out.println(jedis.get("age")); jedis.incr("age"); //把值递增1 System.out.println(jedis.get("age")); jedis.decr("age"); //把值递减1 System.out.println(jedis.get("age")); jedis.del("name"); //根据键删除值 jedis.setnx("name","lye"); //如果key存在不作操作否则直接添加 System.out.println(jedis.get("name")); //根据键取出值 jedis.setex("hobby",10,"lye"); //存入键值对,并设置生命周期 System.out.println(jedis.ttl("hobby")); //查看剩余时间 jedis.close(); pool.destroy();
Hash类型
JedisPool pool = new JedisPool("localhost", 6379); Jedis jedis = pool.getResource(); jedis.hset("user","name","jqy"); //存入一个hash对象 jedis.hset("user","age","18"); System.out.println(jedis.hget("user", "name")); // 根据hash对象键取值 System.out.println(jedis.hexists("user","age")); //判断hash对象是含有某个键 jedis.hdel("user","age"); //根据hashkey删除hash对象键值 System.out.println(jedis.hget("user", "age")); jedis.close(); pool.destroy();
list类型
JedisPool pool = new JedisPool("localhost", 6379); Jedis jedis = pool.getResource(); jedis.rpush("hobby","java","C","C++","lye"); // 往列表右边添加数据 System.out.println(jedis.lrange("hobby", 0, -1)); //范围显示列表数据,全显示则设置0 -1 jedis.lpush("hobby","zakuha"); //往列表左边添加数据 System.out.println(jedis.lpop("hobby")); //弹出列表最左边的数据 System.out.println(jedis.rpop("hobby")); //弹出列表最右边的数据 System.out.println(jedis.llen("hobby")); //获取列表长度 jedis.close(); pool.destroy();
set类型
JedisPool pool = new JedisPool("localhost", 6379); Jedis jedis = pool.getResource(); jedis.sadd("jqy","a","b","c","d","e"); // 往set集合中添加元素 jedis.sadd("lye","e","f","c","d"); System.out.println(jedis.smembers("jqy")); //列出set集合中的元素 jedis.srem("jqy","e"); //删除set集合中的元素 System.out.println(jedis.smembers("jqy")); //列出set集合中的元素 // Set<String> jqy = jedis.spop("jqy", 1); //随机弹出集合中的元素 System.out.println(jedis.sdiff("jqy", "lye")); //返回key1中特有元素(差集) System.out.println(jedis.sinter("jqy","lye")); //返回两个set集合的交集 System.out.println(jedis.sunion("jqy","lye")); // 返回两个set集合的并集 jedis.smove("jqy","lye","a"); //把key1中的某元素移入key2中 System.out.println(jedis.scard("jqy")); //返回set集合中元素个数 jedis.close(); pool.destroy();
sorted-set类型
JedisPool pool = new JedisPool("localhost", 6379); Jedis jedis = pool.getResource(); jedis.zadd("players",3000,"a"); //存入分数和名称 jedis.zadd("players",3000,"b"); jedis.zadd("players",3000,"c"); jedis.zadd("players",3000,"d"); jedis.zincrby("players",2000,"b"); //偏移名称对应的分数 jedis.zincrby("players",4000,"c"); System.out.println(jedis.zrange("players", 0, -1)); //按照分数升序输出名称 System.out.println(jedis.zrevrange("players", 0, -1)); //按照分数降序输出名称 System.out.println(jedis.zrank("players", "b")); //升序返回排名 从0开始 System.out.println(jedis.zrevrank("players", "b")); //降序返回排名 从0开始 System.out.println(jedis.zcard("players"));//返回元素个数 jedis.close(); pool.destroy();
集成springboot
导入依赖
配置文件
获取(RedisTemplate<>对象 )StringRedisTemplate对象
进行操作
redis命令的全称就是spring-data-redis的方法
redis的全局命令在template对象中
String类型
redisTemplate.opsForValue().set("name","jqy"); //存入键值对 redisTemplate.opsForValue().set("age","18"); System.out.println(redisTemplate.opsForValue().get("name")); //根据键取出值 System.out.println(redisTemplate.opsForValue().get("age")); redisTemplate.opsForValue().increment("age"); //把值递增1 System.out.println(redisTemplate.opsForValue().get("age")); redisTemplate.opsForValue().decrement("age"); //把值递减1 System.out.println(redisTemplate.opsForValue().get("age")); redisTemplate.delete("name") ; //根据键删除值 redisTemplate.opsForValue().setIfAbsent("name","lye"); //如果key存在不作操作否则直接添加 System.out.println(redisTemplate.opsForValue().get("name")); //根据键取出值 redisTemplate.opsForValue().set("hobby","lye",Duration.ofSeconds(10)); //存入键值对,并设置生命周期 System.out.println(redisTemplate.getExpire("hobby", TimeUnit.SECONDS)); //查看剩余时间
hash类型
redisTemplate.opsForList().rightPushAll("hobby","java","C","C++","lye"); // 往列表右边添加数据 System.out.println(redisTemplate.opsForList().range("hobby", 0, -1)); //范围显示列表数据,全显示则设置0 -1 redisTemplate.opsForList().leftPush("hobby","zakuha"); //往列表左边添加数据 System.out.println(redisTemplate.opsForList().leftPop("hobby")); //弹出列表最左边的数据 System.out.println(redisTemplate.opsForList().rightPop("hobby")); //弹出列表最右边的数据 System.out.println(redisTemplate.opsForList().size("hobby")); //获取列表长度
set类型
redisTemplate.opsForSet().add("jqy","a","b","c","d","e"); // 往set集合中添加元素 redisTemplate.opsForSet().add("lye","e","f","c","d"); System.out.println(redisTemplate.opsForSet().members("jqy")); //列出set集合中的元素 redisTemplate.opsForSet().remove("jqy","e"); //删除set集合中的元素 System.out.println(redisTemplate.opsForSet().members("jqy")); //列出set集合中的元素 // List<String> jqy = redisTemplate.opsForSet().pop("jqy", 1); //随机弹出集合中的元素 System.out.println(redisTemplate.opsForSet().difference("jqy", "lye")); //返回key1中特有元素(差集) System.out.println(redisTemplate.opsForSet().intersect("jqy","lye")); //返回两个set集合的交集 System.out.println(redisTemplate.opsForSet().union("jqy","lye")); // 返回两个set集合的并集 System.out.println(redisTemplate.opsForSet().move("jqy", "a", "lye")); System.out.println(redisTemplate.opsForSet().size("jqy")); //返回set集合中元素个数
sorted-set类型
redisTemplate.opsForZSet().add("players","a",3000); //存入分数和名称 redisTemplate.opsForZSet().add("players","b",3000); //存入分数和名称 redisTemplate.opsForZSet().add("players","c",3000); //存入分数和名称 redisTemplate.opsForZSet().add("players","d",3000); //存入分数和名称 redisTemplate.opsForZSet().incrementScore("players","b",2000); //偏移名称对应的分数 redisTemplate.opsForZSet().incrementScore("players","c",4000); System.out.println(redisTemplate.opsForZSet().range("players", 0, -1)); //按照分数升序输出名称 System.out.println(redisTemplate.opsForZSet().reverseRange("players", 0, -1)); //按照分数降序输出名称 System.out.println(redisTemplate.opsForZSet().rank("players", "b")); //升序返回排名 从0开始 System.out.println(redisTemplate.opsForZSet().reverseRank("players", "b")); //降序返回排名 从0开始 System.out.println(redisTemplate.opsForZSet().size("players"));//返回元素个数