springboot使用redis对单个对象进行自动缓存更新删除的实现
作者:杉菜酱酱子~ 发布时间:2023-06-30 19:14:36
Springboot的项目搭建在此省略,pom文件依赖什么的就不说了
创建一个实体类
@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;
}
}
创建一个控制器
@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();
}
}
建个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);
}
新建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);
}
}
新建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语句打印,仍然有查询结果成功响应。
@CacheConfig(cacheNames = “repository”)
放在service实现类上,用来配置缓存名称。
@Cacheable(key = “‘safeTypeId:' + #p0”)
放在查询方法上,‘safeTypeId:' + #p0作为键,p0是该方法的第一个参数。
作用:使用这两个注解,会使查询方法首先会根据key从缓存中查询,如果缓存中没有该键,则从使用sql语句到数据库中差查询,查询后,响应结果,并自动将方法的返回结果放入redis缓存中,下一次,如果再查询就直接从redis缓存中查询。
好处:极大提升查询效率,并减轻服务器压力。
@CachePut(key = “‘safeTypeId:' + #p0.safeTypeId”)
通常加到添加和更新方法上
当访问新增题目接口时,数据库新增题目成功,方法返回结果会存入redis中,这次再访问查询属于该分类的题目接口,会发现该分类的题目已经添加成功。
当访问更新题目接口时,数据库更新题目成功,方法返回结果会根据key存入redis中,当再根据该key查询题目时,会发现控制台并没有打印sql语句,直接从redis中查询出结果。
@CacheEvict(key = “#p0”)
用在删除方法上,走该删除方法,会删除数据库中的该条记录,而且会删除key为方法的第一个参数(通常为id)的redis记录。再次查询该条记录,发现查询不到了。
注意:上面的方法不能用来存储集合。
来源:https://blog.csdn.net/qq_45479404/article/details/119303769


猜你喜欢
- 主要思路是调用系统文件管理器或者其他媒体采集资源来获取要上传的文件,然后将文件的上传进度实时展示到进度条中。主Activitypackage
- 前言最近有一项需求,要定时判断任务执行条件是否满足并触发 Spark 任务,平时编写 Spark 任务时都是封装为一个 Jar 包,然后采用
- 前言前两篇我们详细了解了 findById 和 findAll 以及 findAll 的分页查询,如果说JPA只有上面的两种查询功能,那就太
- 本文实例分析了C#中out保留字的用法,分享给大家供大家参考。具体用法分析如下:C#中的out保留字表示这个变量要回传值,最简单的应用是除法
- 在Spring中有一个类CachingUserDetailsService实现了UserDetailsService接口,该类使用静态代理模
- 1、概括在博客中,我们将讨论如何让Spring Security OAuth2实现使用JSON Web Tokens。2、Maven 配置首
- 一、回顾Stream管道流操作通过前面章节的学习,我们应该明白了Stream管道流的基本操作。我们来回顾一下:源操作:可以将数组、集合类、行
- 一、Collection集合Collection接口是单列集合类的父接口,这种集合可以将数据一个一个的存放到集合中。它有两个重要的子接口,分
- 本文实例为大家分享了C#添加PDF文件水印的具体代码,供大家参考,具体内容如下using System;using System.Colle
- // 声明LocationManager对象 LocationManager loctionManager; // 通过系统服务,取得Loc
- 本文实例为大家分享了WPF实现半圆形导航菜单的具体代码,供大家参考,具体内容如下实现效果如下:思路:扇形自定义控件组合成半圆型菜单,再通过c
- 前序格式<meta-data android:name="weather" android:value="
- 一、效果实现二、实现思路:1. 正上方的提示区域,用一个类(LockIndicator.java)来实现,自定义view来绘制9个提示图标;
- 概念装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。装饰者和被装饰对象有相同的超类型。你可以用一个或
- Java反射详解本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的,要不然只看理论的话,看了也不懂,不过建议大家在看完文章之后,
- 在JDK的Collection中我们时常会看到类似于这样的话:例如,ArrayList:注意,迭代器的快速失败行为无法得到保证,因为一般来说
- 前言最近看了一下 Android 上的图表控件,去年做过一款应用也已上架了,也用到了图表控件,但是只是按照官方 demo 集成了,并没有过多
- 这篇文章主要介绍了Spring boot2X负载均衡和反向代理实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参
- 知识点:内部存储空间获取总大小和可用大小;sdcard存储空间获取总大小和可用大小;新名词记录{StatFs:描述文件系统信息的类}概览在开
- 此时希望用户不能通过键盘alt+F4来结束程序及通过Win的组合键对窗口进行操作。我在网上搜索了一下,采用全局键盘钩子的方法可以做到屏蔽用户