Microservice solution - Mybatis-Plus + Redis cache, how to use Redis cache less gracefully

How to use Redis caching less gracefully

We all know to use redisto cache our data collection, as shown in the figure below.

Usually cache the data by yourself. The advantage of this is that the logic is clear, and redisthe keysum valuewill be more standardized. But there will be more redundant codes, and you need to judge whether the data is out of date.
In order to simplify the business code, the redissecond-level cache is now integrated with annotations , but his keysum valuewill be less in compliance with the specification. His keyaltogether contains 5 parts, the most important is the parameter sqlwith this sql. His valueis the result set of this query.

Ready to work

Introduce dependencies,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>

redisrely

<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>

Configuration file

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

ConfigurationredisTemplate

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;
    }
}

Note that Stringthe serialization method I do not use here is deserialization KeyandValue

achieve

Implement Cacheinterface

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;
    }
}

mapperCache the specified configuration

@CacheNamespace(implementation = RedisCache.class)
public interface TbPostMapper extends BaseMapper<TbPost> {
    
    
}

test

Request a database once, use the Debugmode, it keyis one CacheKey, and cannot use StringRedisSerializerdeserialization, so you have redisTemplate to use the default serialization, namely JdkSerializationRedisSerializer

Open it RDMand take a look at library number 4.

Finding the keysum valueis not very beautiful, but it does not affect the use. Of course, you can use it StringRedisSerializerto achieve it, but sqlthere will be a little problem when I get the parameters in the process of trying . Hope someone can point it out.

Sql with parameters

Pay special attention ! In the paging cache, the Pageobject totalmust be manually queried once, otherwise the object returned to the front end will have the total number of pages for the first time, and the second time the cache will not carry this total, so it must be queried manually .

@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);
}

I will continue to update this blog in the future. Well, in the end, I would like to borrow a saying from the big man: "Without a bit of cold, how can you know that the plum blossoms are so sweet".

Guess you like

Origin blog.csdn.net/weixin_42126468/article/details/108697359