复习
- Redis 数据类型 命令
- string
- list
- hash
- set
- sorted set
- redis使用规范
- key设计 命名规范 ugc:user:1
- value设计 避免BigKey
- string长度 大小
- …
- 禁用命令
- 怎么禁用 /etc/redis.conf rename-command flushdb “”
- 禁用 时间复杂度 O(n) keys / flushdb / flushall /config
- hgetall 谨慎使用
- keys hgetall smembers => scan / hscan /zscan /sscan
- scan 游标 match 模式 count 最大返回数量
- Java连接Redis
- jedis 将所有命令转换成方法
- spring-data-redis
- RedisTemplate
- opsForXXX
- boundXXXOps
- RedisTemplate

Redis特性
缓存
@GetMapping("/student/{id}")public Student find(@PathVariable("id")Integer id) throws ParseException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {log.info("查找学生 :{}",id);if(id==null){return null;}Student student = null;//1. 从缓存中获取String stuKey= "stu:"+id;if(redisTemplate.hasKey(stuKey)){log.info("缓存中存在{},从缓存中获取",stuKey);BoundHashOperations ops = redisTemplate.boundHashOps(stuKey);//hash的所有字段,表示学生的所有信息Map<String,Object> entries = ops.entries();log.info("{}",entries);// //转换成student对象 反序列化student = new Student();student.setClassName((String) entries.get("className"));student.setStudentId(Integer.parseInt((String)entries.get("studentId")) );student.setStudentName((String) entries.get("studentName"));student.setStudentNo((String) entries.get("studentNo"));student.setGender((String) entries.get("gender"));student.setAge(Integer.parseInt((String) entries.get("age")));student.setMajor((String) entries.get("major"));//String registerTime = (String) entries.get(entries.get("registerTime"));// student.setRegisterTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(registerTime));student.setCounselor((String) entries.get("counselor"));// student = BeanUtils.mapToBean(entries, Student.class);// student = new Student();// BeanUtils.populate(student,entries);return student;}//2. 从数据库中查询log.info("查询数据库,id=",id);student = studentService.findById(id);//3. 加入到缓存中log.info("存入缓存中{}",student);BoundHashOperations ops = redisTemplate.boundHashOps(stuKey);Map<String, String> stringObjectMap = BeanUtils.describe(student);ops.putAll(stringObjectMap);redisTemplate.expire(stuKey,30, TimeUnit.MINUTES);return student;}
- 不够通用 2. 不够简洁
Spring 缓存抽象 spring cache abstraction
增 @Cachable
删 @CacheEvict
改 @CachePut
查
在application类上加 @EnableCaching
@GetMapping("findById")@Cacheable(cacheNames = "stuCache",key="#stuId")public Student findById(int stuId){log.info("从数据库获取数据{}",stuId);return studentService.findById(stuId);}@PutMapping("updateStu")@CachePut(cacheNames = "stuCache",key = "#student.studentId")public Student updateStudent(@RequestBody Student student){studentService.update(student);return student;}@DeleteMapping("/deleteById")@CacheEvict(cacheNames = "stuCache",key = "#id")public void deleteStudent(int id){studentService.delById(id);}
- pom.xml必须要有redis的依赖, SpringCache 支持多种不同的缓存,其中包括内存缓存,如果没有redis依赖,则使用内存缓存
- 缓存对象,要求加Serializable接口
- 如何查看redis中的缓存?
keys *string缓存配置
spring:redis:host: localhostport: 6379cache:type: redisredis:time-to-live: 60Mkey-prefix: 'redisbootdemo::'
缓存问题

缓存过期的作用=> 保证数据的一致性;减少内存空间;
缓存击穿:有一个key过期时,大量的查询该key的请求,透过redis进入到数据库,key是热点key
- 时间点:在某个key过期 到 该key的缓存重新生成之间
- 解决方案:在缓存过期后,请求加互斥锁
缓存穿透:大量查询不存在的key
- 解决方案:缓存空值;布隆过滤器 BloomFilter(超大的位数组,每1位只有0和1可以表示是否存在)
缓存雪崩:多个key在同一个时间点过期,造成大量的查询透过redis进入到数据库
- 解决方案:设置不同的过期时间
redis缓存支持
指定缓存的内存空间大小 maxmemory 100mb
达到内存上限时如何删除? maxmemory-policy
- noeviction:返回错误,当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)
- allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。
- volatile-lru: 尝试回收最少使用的键(LRU),但仅限于带有过期时间的键,使得新添加的数据有空间存放。
- allkeys-random: 回收随机的键使得新添加的数据有空间存放。
- volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。
- volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。
LRU Least-Recently-Used 最近最少使用
