マイクロサービスソリューション-Mybatis-Plus + Redisキャッシュ、Redisキャッシュの正常な使用方法

Redisキャッシングをあまり適切に使用する方法

redis次の図に示すように、データコレクションのキャッシュにを使用することは誰でも知っています。

通常は自分でデータをキャッシュしますが、その利点はロジックが明確でありrediskey合計valueがより標準化されることです。ただし、冗長なコードが増えるため、データが古いかどうかを判断する必要があります。
ビジネスコードを簡略化するために、redis2次キャッシュは注釈統合されていますが、そのkey合計valueは仕様に準拠していません。彼はkey完全に最も重要であり、5部を含んでいるパラメータsqlこれでsqlvalueはこのクエリの結果セットです。

準備オーケー

依存関係を導入し、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);
}

今後もこのブログを更新していきます。さて、最後に大男の言葉を借りたいと思います。「少し寒くないうちに、梅がとても甘いことをどうやって知ることができますか」。

おすすめ

転載: blog.csdn.net/weixin_42126468/article/details/108697359