springboot使用redis对单个对象进行自动缓存更新删除

Posted 杉菜酱酱子~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot使用redis对单个对象进行自动缓存更新删除相关的知识,希望对你有一定的参考价值。

Springboot的项目搭建在此省略,pom文件依赖什么的就不说了

  1. 创建一个实体类
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@ApiModel(value="ERepository对象", description="题库")
public class ERepository extends BasicModel<ERepository> implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    @ApiModelProperty(value = "安全分类id")
    private Long safeTypeId;

    @ApiModelProperty(value = "题型")
    private Integer quesType;

    @ApiModelProperty(value = "题干")
    private String quesContent;

    @ApiModelProperty(value = "选项")
    private String options;

    @ApiModelProperty(value = "答案")
    private String answer;

    @ApiModelProperty(value = "是否审核(0:未审核,1:已审核)")
//    @TableField("is_check")
    private Boolean isCheck;
    @Override
    protected Serializable pkVal() {
        return this.id;
    }
}
  1. 创建一个控制器
@RequiredArgsConstructor
@RestController
@Slf4j
@Api(tags = "题库模块")
@RequestMapping("/api/eRepository")
public class ERepositoryController {
    private final IERepositoryService eRepositoryService;

    @ApiOperation("查询所有题目")
    @GetMapping(value = "/all")
    @ResponseBody
    public Result<List<ERepository>> getRespository(ERepositoryQueryCriteria criteria){
        return Result.success(eRepositoryService.getRepositoryAll(criteria));
    }

    @ApiOperation(value = "多条件查询题目",notes = "根据各种条件查询,可分页 \\n author:LiFang 2021/7/25")
    @GetMapping
    @ResponseBody
    public Result<IPage<ERepositoryDTO>> getRespository(PageVO pageVO,ERepositoryQueryCriteria criteria){
        return Result.success(eRepositoryService.getRepository(pageVO.buildPage(),criteria));
    }

    @ApiOperation(value = "按安全分类id查询")
    @GetMapping(value = "/getBySafeTypeId")
    public Result<List<ERepository>> getRespositoryBySafeTypeId(Long id){
        Long start = System.currentTimeMillis();
        List<ERepository> list = eRepositoryService.getBySafeTypeId(id);
        Long end = System.currentTimeMillis();
        System.out.println("耗时:"+(end-start));
        return Result.success(list);
    }

    @ApiOperation("新增题目")
    @PostMapping
    public Result<Void> add(@RequestBody ERepository eRepository){
        eRepository.setDeleted(false);
        eRepositoryService.addRepository(eRepository);
        return Result.success();
    }

    @ApiOperation("修改题目")
    @PutMapping
    public Result<Object> update(@RequestBody ERepository eRepository){
        eRepository.setDeleted(false);
        log.info(StrUtil.format("【修改题目 /api/eRepository】操作人id:{},被修改题目id:{}", SecurityUtils.getCurrentUserId(),
                eRepository.getId()));
        return Result.success(eRepositoryService.updateRepository(eRepository));
    }

    @ApiOperation("删除题目")
    @DeleteMapping
    public Result<Void> delete(@RequestBody Set<Long> ids){
        eRepositoryService.deleteById(ids);
        return Result.success();
    }
}
  1. 建个service
public interface IERepositoryService extends IBasicService<ERepository> {
    List<ERepository> getRepositoryAll(ERepositoryQueryCriteria criteria);

    IPage<ERepositoryDTO> getRepository(IPage<ERepository> page,ERepositoryQueryCriteria criteria);

    List<ERepository> addRepository(ERepository eRepository);

    List<ERepository> updateRepository(ERepository eRepository);

    void deleteById(Set<Long> id);

    List<ERepository> getBySafeTypeId(Long id);
}

  1. 新建service实现类
    使用注解进行自动缓存、更新、删除主要是在service的实现类里写
@Slf4j
@Service
@EnableCaching
@RequiredArgsConstructor
@CacheConfig(cacheNames = "repository")
public class ERepositoryServiceImpl extends BasicServiceImpl<ERepositoryMapper, ERepository> implements IERepositoryService {
    private final ERepositoryMapper eRepositoryMapper;
    private final ERepositoryStruct eRepositoryStruct;
//    private final ERepositoryServiceImpl eRepositoryService;
    private final RedisUtils redisUtils;

    @Override
    public List<ERepository> getRepositoryAll(ERepositoryQueryCriteria criteria) {
        List<ERepository> eRepositories = eRepositoryMapper.selectList(buildERepositoryCriteria(criteria));
        return eRepositories;
    }

    @Override
    public IPage<ERepositoryDTO> getRepository(IPage<ERepository> page,ERepositoryQueryCriteria criteria) {
        IPage<ERepository> eRepositoryPage = eRepositoryMapper.selectPage(page,buildERepositoryCriteria(criteria));
        List<ERepositoryDTO> eRepositoryDTOList = eRepositoryStruct.toDto(eRepositoryPage.getRecords());
        return PageUtil.toMapStructPage(eRepositoryPage,eRepositoryDTOList);
    }

    @Cacheable(key = "'safeTypeId:' + #p0")
    @Override
    public List<ERepository> getBySafeTypeId(Long id) {
        List<ERepository> eRepositoryList = eRepositoryMapper.getBySafeTypeId(id);
        return eRepositoryList;
    }

    private LambdaQueryWrapper<ERepository> buildERepositoryCriteria(ERepositoryQueryCriteria criteria){
        LambdaQueryWrapper<ERepository> wrapper = new LambdaQueryWrapper<>();
//        wrapper.eq(ERepository::getDeleted,false);
        if (ObjectUtil.isNotNull(criteria.getId())) {
            wrapper.eq(ERepository::getId,criteria.getId());
        }
        if(StrUtil.isNotBlank(criteria.getQuesContent())){
            //默认使用like匹配
            wrapper.like(ERepository::getQuesContent, criteria.getQuesContent());
        }
        if (ObjectUtil.isNotNull(criteria.getSafeTypeId())) {
            wrapper.eq(ERepository::getSafeTypeId, criteria.getSafeTypeId());
        }
        if(ObjectUtil.isNotNull(criteria.getQuesType())){
            wrapper.eq(ERepository::getQuesType,criteria.getQuesType());
        }
        if (ObjectUtil.isNotNull(criteria.getStartTime()) && ObjectUtil.isNotNull(criteria.getEndTime())) {
            wrapper.between(ERepository::getCreateTime , criteria.getStartTime(), criteria.getEndTime());
        }
        return wrapper;
    }

    @CachePut(key = "'safeTypeId:' + #p0.safeTypeId")
    @Override
    public List<ERepository> addRepository(ERepository eRepository) {
        eRepositoryMapper.insert(eRepository);
        List<ERepository> list = eRepositoryMapper.getBySafeTypeId(eRepository.getSafeTypeId());
//        list.add(eRepository);
        return list;
    }

    @CachePut(key = "'safeTypeId:' + #p0.safeTypeId")
    @Override
    public List<ERepository> updateRepository(ERepository resources) {
        ERepository eRepository = getById(resources.getId());
        if(ObjectUtil.isEmpty(eRepository)){
            log.error(StrUtil.format("【修改题目失败】操作人id:{},修改目标ERepository为空,目标id:{}", SecurityUtils.getCurrentUserId(),
                    resources.getId()));
            throw new BadRequestException("修改失败,当前数据id不存在");
        }
        eRepositoryMapper.updateById(resources);
        log.info(StrUtil.format("【修改题目成功】操作人id:{},修改目标题目:{}", SecurityUtils.getCurrentUserId(),
                resources));
        List<ERepository> list = eRepositoryMapper.getBySafeTypeId(resources.getSafeTypeId());
//        list.removeIf(item -> resources.geMId().equals(item.getId()));
//        list.add(resources);
        //清理缓存
        delCaches(resources.getId());
        return list;
    }

    @Override
    public void deleteById(Set<Long> ids) {
        for (Long id : ids){
            eRepositoryMapper.deleteById(id);
            //清理缓存
            delCaches(id);
        }
        log.info(StrUtil.format("【删除题目成功】操作人id:{},删除目标repositories:{}", SecurityUtils.getCurrentUserId(),
                ids.toString()));
    }

    /**
     * 清理缓存
     *
     * @param id /
     */
    private void delCaches(Long id) {
        Long safeTypeId = eRepositoryMapper.getSafeTypeIdById(id);
        //删除属于该安全分类的题库缓存
        redisUtils.del(CacheKey.REPOSITORY_SAFETYPEID + safeTypeId);
    }
}
  1. 新建mapper接口
@Component
public interface ERepositoryMapper extends BasicMapper<ERepository> {
    @Select("SELECT * FROM e_repository WHERE safe_type_id = #{safeTypeId} AND is_deleted=0")
    List<ERepository> getBySafeTypeId(Long safeTypeId);

     @Select("SELECT safe_type_id FROM e_repository WHERE id= #{id} AND is_deleted=0")
     Long getSafeTypeIdById(Long id);
}

6.启动项目
使用swagger测试根据安全分类id查询题目接口,该分类题目的查询结果成功响应,这时打开redis管理工具,可以看到题目按分类已经被缓存到redis中了。

再次用swagger测试查询该分类id的所有题目,可以看到IDEA控制台并没有sql语句打印,仍然有查询结果成功响应。

  1. @CacheConfig(cacheNames = “repository”)
    放在service实现类上,用来配置缓存名称。
  2. @Cacheable(key = “‘safeTypeId:’ + #p0”)
    放在查询方法上,‘safeTypeId:’ + #p0作为键,p0是该方法的第一个参数。

作用:使用这两个注解,会使查询方法首先会根据key从缓存中查询,如果缓存中没有该键,则从使用sql语句到数据库中差查询,查询后,响应结果,并自动将方法的返回结果放入redis缓存中,下一次,如果再查询就直接从redis缓存中查询。

好处:极大提升查询效率,并减轻服务器压力。

  1. @CachePut(key = “‘safeTypeId:’ + #p0.safeTypeId”)

    通常加到添加和更新方法上

  • 当访问新增题目接口时,数据库新增题目成功,方法返回结果会存入redis中,这次再访问查询属于该分类的题目接口,会发现该分类的题目已经添加成功。
  • 当访问更新题目接口时,数据库更新题目成功,方法返回结果会根据key存入redis中,当再根据该key查询题目时,会发现控制台并没有打印sql语句,直接从redis中查询出结果。
  1. @CacheEvict(key = “#p0”)
    用在删除方法上,走该删除方法,会删除数据库中的该条记录,而且会删除key为方法的第一个参数(通常为id)的redis记录。再次查询该条记录,发现查询不到了。

注意:上面的方法不能用来存储集合。

以上是关于springboot使用redis对单个对象进行自动缓存更新删除的主要内容,如果未能解决你的问题,请参考以下文章

Redis - Springboot中集成多个Redis客户端统一管理

Spring Boot 之Redis

springboot 集成redis 和http请求

Spring Boot教程(三十四)使用Redis数据库

SpringBoot :Spring boot 中 Redis 的使用

SpringBoot整合Redis