Redisキャッシングをあまり適切に使用する方法
redis
次の図に示すように、データコレクションのキャッシュにを使用することは誰でも知っています。
通常は自分でデータをキャッシュしますが、その利点はロジックが明確でありredis
、key
合計value
がより標準化されることです。ただし、冗長なコードが増えるため、データが古いかどうかを判断する必要があります。
ビジネスコードを簡略化するために、redis
2次キャッシュは注釈と統合されていますが、その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.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
シリアル化方法は、逆シリアル化で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 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> {
}
テスト
データベースを1回要求し、Debug
モードを使用します。モードkey
は1 CacheKey
であり、非StringRedisSerializer
直列化を使用できないため、デフォルトの直列化を使用する必要がredisTemplate
あります。 JdkSerializationRedisSerializer
それRDM
を開いて、ライブラリー番号4を見てください。
key
合計を見つけることvalue
はあまり美しくありませんが、使用には影響しません。もちろん、それを使用してそれStringRedisSerializer
を達成することはsql
できますが、を試行する過程でパラメーターを取得するときに少し問題があります。誰かがそれを指摘できることを願っています。
SQLとパラメーター
特に注意してください!ページングキャッシュでは、Page
オブジェクトをtotal
手動で1回クエリする必要があります。そうしないと、フロントエンドに返されたオブジェクトには最初に合計ページ数が含まれ、2回目はキャッシュにこれが含まれないため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);
}
今後もこのブログを更新していきます。さて、最後に大男の言葉を借りたいと思います。「少し寒くないうちに、梅がとても甘いことをどうやって知ることができますか」。