Redis
redis是一个基于内存的key-value结构的NoSQL数据库
访问数据量高的话可以用Redis
默认端口号6379
NoSQL
关系型数据库是数据库和数据库之间存在关系,但是存在磁盘上,读写数据比较差。
而NoSQL是非关系型数据库,格式比较灵活
Redis数据类型
注:redis里面的null是nil
字符串String
1 2 3 4 5 6 7 8
| 新增:set key value 如果value有空格,要用引号引起来 查询:get key 删除:del key 新增的时候设置过期时间: setex key 过期时间 value 查看剩余时间:ttl key 根据键判断记录是否存在:exists key 新增的时候判断是否存在:setnx key value 自增/减操作:incre/decr key
|
哈希(大的map套一个小map)
1 2 3 4 5 6 7 8
| 新增:hset key hkey hvalue hset 大键 小键 值 可以理解为把键值对存到一个大键中 查询:所有 hgetall key 单个 hget key hkey 获取所有hkey(小键): hkeys key 获取所有hvalue: hvals key 删除: 单个 hdel key hkey 所有 del key 修改就是覆盖,直接新增原来的名字就可以
|
列表list(有序且重复)是一个双向链表,添加的时候是可以从头添加,也可以从尾添加,但查询的时候只能从左开始查询
1 2 3 4 5 6 7
| 新增:左压 lpush key value 右压 rpush key value 查询元素: lrange key [开始索引 结束索引] 最后一个索引是-1 查询列表长度: llen key 删除元素; 左弹 lpop key 右弹 rpop key
|
集合set(hash表,无序,不可重复)
1 2 3 4 5 6 7 8 9 10
| 新增: sadd key value 查询元素: smembers key 查询集合数量:scard key 删除元素:srem key value 比如添加小明的爱好: asdd ming it music sport 添加小红的爱好: asdd hong it music tiaowu 求集合的交集: sinter key1 key2 比如查小明和小红共同的爱好(交集): sinter ming hong 结果就是 it music 求集合的并集: sunion key1 key2 同上查询全部的爱好(并集):sunion ming hong 结果 it music sport tiaowu
|
有序集合zset(有序,不可重复)
1 2 3 4 5 6 7 8 9 10
| 新增: zadd key score value score是分数,指定分数会按照分数排序 查询: 升序 zrange key start end [withscores] 降序 zrevrange key start end [withscores] 比如新增语文成绩排名: zadd yuwen 81 ming zadd yuwen 86 hong 加分: zincrby key increment member 比如小明语文加10分: zincrby yuwen 10 ming 删除: zrem key value
|
通用命令
模糊查询键
删除多个键
根据键判断值类型
选择数据库: 默认有16个数据库
用java操作Redis
Spring对Redis进行了整合,提供了Spring Data Redis,它将所有的类型命令封装到了一个类中,名字叫: RedisTemplate
导入坐标:
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
|
添加redis配置:
1 2 3 4 5 6 7 8 9 10 11
| sky: redis: host: localhost port: 6379 password: itheima
spring: redis: host: ${sky.redis.host} port: ${sky.redis.port} password: ${sky.redis.password}
|
如果要让一个java对象存到Redis内存中,必须要实现序列化接口!
1
| 实体类 implements Serializable
|
字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ValueOperations valueOperations = redisTemplate.opsForValue();
valueOperations.set("小明", 18);
valueOperations.get("小明");
valueOperations.set("手机号:111","1024", Duration.ofSeconds(300));
Category category = new Category(); category.setName("羽毛球"); valueOperations.set("对象",category);
valueOperations.get("对象");
|
列表
1 2 3 4 5 6 7 8 9 10 11 12
| ListOperations listOperations = redisTemplate.opsForList();
listOperations.leftPushAll("泡泡","a","b","c");
List mylist = listOperations.range("泡泡", 0, -1); System.out.println(mylist);
System.out.println(listOperations.rightPop("泡泡"));
List mylist1 = listOperations.range("泡泡", 0, -1); System.out.println(mylist1);
|
哈希
1 2 3 4 5 6 7 8 9 10 11 12 13
| HashOperations hashOperations = redisTemplate.opsForHash();
hashOperations.put("大key","小key","值"); hashOperations.put("语文","小明",89); hashOperations.put("语文","小红",99);
hashOperations.get("语文", "小明");
Set hkeys = hashOperations.keys("语文"); for (Object key : hkeys) { hashOperations.get("语文", key); }
|
集合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| SetOperations setOperations = redisTemplate.opsForSet();
Set set = setOperations.members("ming"); System.out.println(set);
System.out.println(setOperations.intersect("caixukun", "ming"));
System.out.println(setOperations.union("caixukun", "ming"));
setOperations.remove("caixukun","rap");
|
有序集合
1 2 3 4 5 6 7 8 9 10
| ZSetOperations zSetOperations = redisTemplate.opsForZSet();
zSetOperations.incrementScore("语文","安其拉",30);
System.out.println(zSetOperations.reverseRange("语文", 0, -1));
|
公共代码
1 2 3 4 5 6 7
| Set keys = redisTemplate.keys("c*"); System.out.println(keys);
redisTemplate.delete(keys);
System.out.println(redisTemplate.hasKey("caixukun"));
|
案例:后台管理端有个营业中和打烊中,只要一个1和0的值,存sql数据库比较多余,所以这里可以存储到Redis
前端需要一个1或者0,我们通过键存储值,前端设置店铺状态为打烊就会传过来一个1,然后我们通过Redis存储到Redis数据库中。然后查询店铺状态的时候,从Redis中获取到值返回即可
小程序端要同步的话,同样从Redis中获取值返回即可
在高并发的情况下,频繁查询会使数据库性能下降,我们可以对其进行优化,添加缓存功能:
适合经常访问但不经常修改的数据放在Redis中比较优~
把即将查询到的数据保存到Redis中,在数据库不变化的情况下,后面的查询从Redis中读取数据,就能提高查询性能
用户访问过一次后,会去sql数据库查询数据,之后把查询到的数据保存到到Redis缓存,下次用户再查询的时候,会从Redis缓存中获取数据,提高性能
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
| @Autowired private DishService dishService;
@Autowired 调用Redis private RedisTemplate redisTemplate;
@GetMapping("/list") public Result getList(@RequestParam Long categoryId) { List<DishVO> voList = null; String dishKey = "DISH:" + categoryId; if (redisTemplate.hasKey(dishKey)) { log.info("查询缓存..."); voList = (List<DishVO>) redisTemplate.opsForValue().get(dishKey); return Result.success(voList); } DishPageDTO dishPageDTO = DishPageDTO.builder() .categoryId(categoryId) .status(1) .build(); log.info("查询数据库..."); voList = dishService.getParamList(dishPageDTO); redisTemplate.opsForValue().set(dishKey, voList); return Result.success(voList); }
|
如果修改了数据库的数据,但用户访问的时候还是读取的缓存,会出现脏读,我们必须保持数据一致性
我们需要在新增,修改,删除的时候清理缓存,在执行完操作后清理缓存,我们id是从菜品分类id中获取的,所以通过菜品分类id清理就可以了
1
| redisTemplate.delete("DISH:"+dishDTO.getCategoryId());
|
修改菜品的时候,有可能会改,有可能不会改,所以为了保险起见,我们直接把修改的所有缓存都清理
1 2
| Set dishKey = redisTemplate.keys("DISH*"); redisTemplate.delete(dishKey);
|
同时批量删除的时候前端只传了菜品的id,没有传分类id,所以这里我们也需要全部清理缓存