微服务解决方案 — Mybatis-Plus + Redis缓存,如何不太优雅的使用Redis缓存


如何不太优雅的使用Redis缓存

我们都知道使用redis来缓存我们的数据集合,如下图所示。
微服务解决方案 -- Mybatis-Plus + Redis缓存,如何不太优雅的使用Redis缓存

通常自己去缓存数据,这样的优点就是逻辑清晰,而且rediskeyvalue会比较规范。但是冗余代码会比较多,需要自己进行判断数据是否过期。
为了简化业务代码,现在用注解的方式集成redis二级缓存,但是他的keyvalue就会比较不符合规范。他的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.HikariDataSource
driver-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=false
username: root
password: 123456
hikari:
minimum-idle: 5
idle-timeout: 600000
maximum-pool-size: 10
auto-commit: true
pool-name: MyHikariCP
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
# redis
redis:
host: xxx.xxx.xxx.xxx
port: 6379
lettuce:
pool:
max-active: 8
max-idle: 8
max-wait: -1ms
min-idle: 0
database: 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的序列化方式去序列化KeyValue

实现

实现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 id
private 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;
}

@Override
public String getId() {
return id;
}

/**
* Put query result to redis
*
* @param key
* @param value
*/
@Override
public 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
*/
@Override
public 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
*/
@Override
public 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
*/
@Override
public int getSize() {
return 0;
}

@Override
public 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
微服务解决方案 -- Mybatis-Plus + Redis缓存,如何不太优雅的使用Redis缓存

打开RDM,看一下4号库。

微服务解决方案 -- Mybatis-Plus + Redis缓存,如何不太优雅的使用Redis缓存

发现keyvalue就不是很美观,不过不影响使用,当然您可以使用StringRedisSerializer去实现,只不过我在尝试的过程中获取sql和参数的时候,会出现一点问题。希望有大佬可以指出。

带参数的sql

微服务解决方案 -- Mybatis-Plus + Redis缓存,如何不太优雅的使用Redis缓存

特别注意! 在分页缓存的时候,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);
}

后续我也会继续更新这篇博客。好了,最后还是借用大佬的一句话:“不经一番寒彻骨,怎知梅花扑鼻香”。

原创:https://www.panoramacn.com
源码网提供WordPress源码,帝国CMS源码discuz源码,微信小程序,小说源码,杰奇源码,thinkphp源码,ecshop模板源码,微擎模板源码,dede源码,织梦源码等。

专业搭建小说网站,小说程序,杰奇系列,微信小说系列,app系列小说

微服务解决方案 -- Mybatis-Plus + Redis缓存,如何不太优雅的使用Redis缓存

免责声明,若由于商用引起版权纠纷,一切责任均由使用者承担。

您必须遵守我们的协议,如果您下载了该资源行为将被视为对《免责声明》全部内容的认可-> 联系客服 投诉资源
www.panoramacn.com资源全部来自互联网收集,仅供用于学习和交流,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。 敬请谅解! 侵权删帖/违法举报/投稿等事物联系邮箱:2640602276@qq.com
未经允许不得转载:书荒源码源码网每日更新网站源码模板! » 微服务解决方案 — Mybatis-Plus + Redis缓存,如何不太优雅的使用Redis缓存
关注我们小说电影免费看
关注我们,获取更多的全网素材资源,有趣有料!
120000+人已关注
分享到:
赞(0) 打赏

评论抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

您的打赏就是我分享的动力!

支付宝扫一扫打赏

微信扫一扫打赏