微服务解决方案 -- Mybatis-Plus + Redis缓存,如何不太优雅的使用Redis缓存
如何不太优雅的使用Redis缓存
我们都知道使用redis
来缓存我们的数据集合,如下图所示。
通常自己去缓存数据,这样的优点就是逻辑清晰,而且redis
的key
和value
会比较规范。但是冗余代码会比较多,需要自己进行判断数据是否过期。
为了简化业务代码,现在用注解的方式集成redis
二级缓存,但是他的key
和value
就会比较不符合规范。他的key
一共包含5个部分,最重要的就是sql
和这个sql
的参数。他的value
就是这个查询的结果集。
准备工作
引入依赖,mybatis
<dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId><exclusions><!-- 排除 tomcat-jdbc 以使用 HikariCP --><exclusion><groupId>org.apache.tomcat</groupId><artifactId>tomcat-jdbc</artifactId></exclusion></exclusions>
</dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.0.6</version>
</dependency>
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-extension</artifactId><version>3.0.6</version>
</dependency>
redis
依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>
配置文件
spring:datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driver# 这里使用的是 ip:3336/db_order 的数据库(一个服务一个数据库)url: jdbc:mysql://localhost:3306/sys-common?useUnicode=true&characterEncoding=utf-8&serverTimezone=Hongkong&useSSL=falseusername: rootpassword: 123456hikari:minimum-idle: 5idle-timeout: 600000maximum-pool-size: 10auto-commit: truepool-name: MyHikariCPmax-lifetime: 1800000connection-timeout: 30000connection-test-query: SELECT 1# redisredis:host: xxx.xxx.xxx.xxxport: 6379lettuce:pool:max-active: 8max-idle: 8max-wait: -1msmin-idle: 0database: 4
配置redisTemplate
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;/*** ProjectName: hello-redis-cache* Package: com.laoshiren.hello.redis.cache.mybatis.configure* ClassName: RedisConfiguration* Author: laoshiren* Description:* Date: 2020/9/13 15:49* Version: 1.0*/
@Configuration
public class RedisConfiguration {/*** 设置redisTemplate*/@Bean(name = "redisTemplate")public RedisTemplate<Object, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);// 使用String 序列化
// redisTemplate.setDefaultSerializer(new StringRedisSerializer());
// redisTemplate.setKeySerializer(new StringRedisSerializer());
// redisTemplate.setValueSerializer(new StringRedisSerializer());redisTemplate.afterPropertiesSet();return redisTemplate;}
}
注意这里我不使用String
的序列化方式去序列化Key
和Value
实现
实现Cache
接口
package com.laoshiren.hello.redis.cache.mybatis.cache;import com.laoshiren.hello.redis.cache.mybatis.configure.ApplicationContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;/*** ProjectName: hello-redis-cache* Package: com.laoshiren.hello.redis.cache.mybatis.cache* ClassName: RedisCache* Author: laoshiren* Description:* Date: 2020/9/13 15:34* Version: 1.0*/
@Slf4j
public class RedisCache implements Cache {private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();private final String id; // cache instance idprivate RedisTemplate redisTemplate;private static final long EXPIRE_TIME_IN_MINUTES = 30; // redis过期时间public RedisCache(String id) {if (id == null) {throw new IllegalArgumentException("Cache instances require an ID");}this.id = id;}@Overridepublic String getId() {return id;}/*** Put query result to redis** @param key* @param value*/@Overridepublic void putObject(Object key, Object value) {try {RedisTemplate redisTemplate = getRedisTemplate();redisTemplate.opsForValue().set(key, value, EXPIRE_TIME_IN_MINUTES, TimeUnit.MINUTES);log.debug("Put query result to redis");} catch (Throwable t) {log.error("Redis put failed", t);}}/*** Get cached query result from redis** @param key* @return*/@Overridepublic Object getObject(Object key) {try {RedisTemplate redisTemplate = getRedisTemplate();log.info("Get cached query result from redis");
// System.out.println("****" + opsForValue.get(key).toString());return redisTemplate.opsForValue().get(key);} catch (Throwable t) {log.error("Redis get failed, fail over to db", t);return null;}}/*** Remove cached query result from redis** @param key* @return*/@Override@SuppressWarnings("unchecked")public Object removeObject(Object key) {try {RedisTemplate redisTemplate = getRedisTemplate();redisTemplate.delete( key.toString());log.debug("Remove cached query result from redis");} catch (Throwable t) {log.error("Redis remove failed", t);}return null;}/*** Clears this cache instance*/@Overridepublic void clear() {RedisTemplate redisTemplate = getRedisTemplate();redisTemplate.execute((RedisCallback) connection -> {connection.flushDb();return null;});log.debug("Clear all the cached query result from redis");}/*** This method is not used** @return*/@Overridepublic int getSize() {return 0;}@Overridepublic ReadWriteLock getReadWriteLock() {return readWriteLock;}private RedisTemplate getRedisTemplate() {if (redisTemplate == null) {redisTemplate = ApplicationContextHolder.getBean("redisTemplate");}return redisTemplate;}
}
给指定的mapper
配置缓存
@CacheNamespace(implementation = RedisCache.class)
public interface TbPostMapper extends BaseMapper<TbPost> {}
测试
请求一次数据库,使用Debug
模式,它的key
是一个CacheKey
,无法使用使用StringRedisSerializer
去序列化,所以redisTemplate
得使用默认的序列化,即 JdkSerializationRedisSerializer
打开RDM
,看一下4号库。
发现key
和value
就不是很美观,不过不影响使用,当然您可以使用StringRedisSerializer
去实现,只不过我在尝试的过程中获取sql
和参数的时候,会出现一点问题。希望有大佬可以指出。
带参数的sql
特别注意! 在分页缓存的时候,Page
对象的total
必须自己手动查询一次,不然返回给前端的对象里第一次还有总页数,第二次由于走了缓存就不带这个total
,所以必须手动查询一次。
@GetMapping("page/{pageNo}/{pageSize}")
public ResponseResult<IPage<Area>> page(@PathVariable(name = "pageNo")Integer pageNo,@PathVariable(name = "pageSize") Integer pageSize,HttpServletRequest request){IPage<Area> wherePage = new Page<>(pageNo, pageSize);String word = request.getParameter("wd");LambdaQueryWrapper<Area> queryWrapper = new LambdaQueryWrapper<>();if (StringUtils.isNotBlank(word)) {queryWrapper.like(Area::getAreaName,word);}int count = areaService.count(queryWrapper);IPage<Area> page = areaService.page(wherePage,queryWrapper);page.setTotal((long)count);return new ResponseResult<>(CodeStatus.OK,"操作成功",page);
}
后续我也会继续更新这篇博客。好了,最后还是借用大佬的一句话:“不经一番寒彻骨,怎知梅花扑鼻香”。
微服务解决方案 -- Mybatis-Plus + Redis缓存,如何不太优雅的使用Redis缓存相关推荐
- 【Spring Cloud】03_SpringCloud Alibaba 微服务解决方案
微服务简介 背景分析 讲微服务之前,我们先分析以下单体应用.所谓单体应用一般是基于idea/eclipse,maven等建一个工程,然后基于SpringBoot,spring,mybatis框架进行整 ...
- Spring Cloud Alibaba 新一代微服务解决方案
本篇是「跟我学 Spring Cloud Alibaba」系列的第一篇, 每期文章会在公众号「架构进化论」进行首发更新,欢迎关注. 1.Spring Cloud Alibaba 是什么 Spring ...
- openfeign调用服务是否需要网关_阿里新一代微服务解决方案:Spring Cloud Alibaba
1.Spring Cloud Alibaba 是什么 Spring Cloud Alibaba 是阿里巴巴提供的微服务开发一站式解决方案,是阿里巴巴开源中间件与 Spring Cloud 体系的融合. ...
- 基于yaf+yar微服务解决方案教程
基于yaf+yar微服务解决方案教程 大纲 主要内容 [课程地址](https://edu.csdn.net/course/detail/9933) 大纲 主要内容 课程地址
- 微服务解决方案_微服务为您提供正确的解决方案
微服务解决方案 I have been writing about Microservices for quite a few years, both its benefits and its dow ...
- SpringCloud核心技术 | 初识SpringCloud微服务解决方案
最近这几个月文章更新处于停滞状态,因为公司的事情比较多,公司系统一直处于高速的迭代更新阶段, 尽管如此,我这段时间也一直在整理接下来要更新的文章大纲以及知识点的梳理,希望在后续的文章更新中能给这段时间 ...
- nodejs微服务解决方案
前言 seneca是一个nodejs微服务工具集,它赋予系统易于连续构建和更新的能力.下面会逐一和大家一起了解相关技术入门以及实践. 这里插入一段硬广.小子再进行简单整合之后撸了个vastify框架 ...
- SpringCloud Alibaba微服务解决方案
文章目录 环境搭建 服务调用--RestTemplate 服务治理--Nacos 负载均衡--Ribbon 服务调用--OpenFeign 服务容错--Sentinel 流控规则 降级规则 热点规则 ...
- spring boot微服务架构mybatis多数据源切换
1,先看个目录结构图 可以看到,我把要设置的配置文件都放在了config文件夹下面 2,Application.java是程序启动项,里面必须设置 3,application.properties是多 ...
最新文章
- TensorFlow练习26: AI操盘手
- Java8 ArrayBlockingQueue 源码阅读
- java–jwt_java – Spring引导如何使用jwt管理用户角色
- [SlickEdit] SlickEdit支持目录别名FTP控件更新
- spring cloud eureka注册原理-注册失败填坑
- 全网首发Oreo易支付开源+教程
- 如何才能通过设置将excel单元格内的14位数字转换为日期格式
- 都说「跳一跳」是微信抄袭了育碧,万万没想到,他们在一起了!
- C++11模板友元语法
- 3t硬盘 xp_解决方案:如何在Windows XP SP3 32位系统下识别3T容​​量GPT格式的硬盘...
- Android TTS实现简单阅读器(一)
- 计算机网络 第七版-第七版第八章软件工程(含答案)
- ASPJpeg和ASPUpload组件的一些属性和方法
- 微信小程序与普通网页区别
- 微信小程序地图篇(腾讯地图)
- MySQL高级-(存储引擎、索引、锁)
- MP条件构造器Wrapper
- π的值(已算到6086位)
- Codeforces 1633 E. Spanning Tree Queries ——暴力,kruskal,思维
- Android网络开发技术实战详解
热门文章
- (Div.2)D. Edge Deletion
- 介绍五种“去火”食疗法
- 16种常用的数据分析方法-信度分析
- 求3+33+333+3333+33333......的值
- k8s podPreset更改所有容器时间为当地时间。
- 关于HSL和HSV颜色空间的详细论述
- 用假名印名片犯法吗_用简单的javascript学习假名
- 【JVM】 双亲委派机制
- Spanner 论文小结
- JDK 1.8 免积分下载