type
Post
status
Published
date
Jan 6, 2021
slug
summary
基本的 Redis 缓存和回写操作示例
tags
Redis
category
技术分享
icon
password

查询

查询先查 Reids
  • 先从 Redis 里查询,如果有数据直接返回,没有再去查询 Mysql
  • 从 MySQL 查询到数据后,需要将数据写回 Redis 以保障下一次缓存命中
    •      User user = null;      String key = CACHE_KEY_USER+id;      //先从redis里面查询      user = (User) redisTemplate.opsForValue().get(key);      if(user == null)     {          // redis里面无,继续查询mysql          user = userMapper.selectByPrimaryKey(id);          if(user == null)         {              //都无数据,返回空数据              return user;         }else{              //数据写回 redis              redisTemplate.opsForValue().set(key,user);         }     }      return user;

实际生产环境中,通常 redis 的 key 都会设置过期时间,如果正好遇到过期时间到期,某个热点 key 突然失效,会导致缓存击穿问题
击穿:缓存先击中(一开始 Redis 中有数据),但热点 key 突然失效

改进

为了避免缓存击穿,要保证只有一个请求操作,其他请求等待
借鉴单例模式的双锁检测( Double Check)思想
      user = (User)redisTemplate.opsForValue().get(key); //第一重检测        if(user == null)       {           //进来就加锁,保证一个请求操作            synchronized (UserService.class){                //加锁后再查一次 redis                user = (User) redisTemplate.opsForValue().get(key);                //第二重检测,如果二次 Redis 还是 null,就可以去查MySQL 了                if (user == null) {                    user = userMapper.selectByPrimaryKey(id);                    if (user == null) { //如果还是 null ,刚才被人删了                        return null;                   }else{ //回写 redis 完成一致性的同步工作                     /redisTemplate.opsForValue().setIfAbsent(key,user,7L,TimeUnit.DAYS);                   }               }           }       }        return user;

增删改

修改先操作 MySQL
插入用户数据时做第二次判断
  • 不仅判断返回的 int 行数 > 1,还要重新查出一次确保正确的插入
  • 删除:保证先操作数据库再操作 Redis
    • 生产环境下使用逻辑删除居多,方便演示直接使用物理删除
    • int i = userMapper.deleteByPrimaryKey(id); if(i > 0) {  String key = CACHE_KEY_USER+id;  redisTemplate.delete(key); }
  • 修改:同样使用修改操作后查询出的数据修改 Redis
    • int i = userMapper.updateByPrimaryKeySelective(user); if(i > 0) { user = userMapper.selectByPrimaryKey(user.getId()); String key = CACHE_KEY_USER+user.getId(); redisTemplate.opsForValue().set(key,user); }
常见三大数据库连接池使用及工具类抽取SSM框架整合:分层配置和整合