Sringboot2.x integrates Redis cache and sets expiration time

Directory Structure:

pom.xml

<dependencies>
        <!--Spring整合redis包 -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.1</version>
        </dependency>
        <dependency>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.5.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.68</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>
    </dependencies>

application.properties

# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=0

spring.datasource.url= jdbc:mysql://localhost:3306/cache-db?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
spring.datasource.username= root
spring.datasource.password= 123456
spring.datasource.driver-class-name= com.mysql.jdbc.Driver

mybatis-plus.mapper-locations= classpath:mapper/*.xml
RedisConfig
package com.frank.cache.config;

import org.springframework.beans.factory.annotation.Value;
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.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.io.Serializable;

/**
 * @author 小石潭记
 * @date 2020/6/26 12:44
 * @Description: ${todo}
 */
@Configuration
public class RedisConfig {

    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.timeout}")
    private int timeout;

    @Bean
    public RedisTemplate<Object, Serializable> redisTemplate(LettuceConnectionFactory connectionFactory) {
        RedisTemplate<Object, Serializable> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setConnectionFactory(connectionFactory);
        return redisTemplate;
    }

}
ArticleController
package com.frank.cache.controller;

import com.frank.cache.entity.Article;
import com.frank.cache.entity.ResultVo;
import com.frank.cache.mapper.ArticleMapper;
import com.frank.cache.service.ArticleRedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @author 小石潭记
 * @date 2020/6/26 11:30
 * @Description: ${todo}
 */
@RestController
@Slf4j
public class ArticleController {

    @Autowired
    private ArticleRedisService service;

    @Autowired
    ArticleMapper articleMapper;

    /**
     * 添加文章
     */
    @PostMapping("/add")
    public ResultVo addArticle(@RequestBody Article article) {
        log.info(article.toString());
        Integer result = service.addArticle(article);
        if (result >= 0) {
            return ResultVo.success(article);
        }
        return ResultVo.fail();
    }

    /**
     * 获取一篇文章
     */
    @GetMapping("/get")
    public ResultVo getArticle(@RequestParam("id") Integer id) {
        Long start = System.currentTimeMillis();
        Article article = service.getArticle(id);
        Long end = System.currentTimeMillis();
        log.info("耗时:"+ (end-start));
        if (null != article)
            return ResultVo.success(article);
        return ResultVo.fail();
    }

    @GetMapping("/getAll")
    public ResultVo getAllArticles() {
        Long start = System.currentTimeMillis();
        Object articles = service.getAllArticles();
        Long end = System.currentTimeMillis();
        log.info("耗时:"+(end-start));
        if (null != articles) {
            return ResultVo.success(articles);
        }
        return ResultVo.fail();
    }

    /**
     * 更新一篇文章
     */
    @PostMapping("/update")
    public ResultVo update(@RequestBody Article article) {
        final Integer result = service.update(article);
        if (result > 0) {
            return ResultVo.success(result);
        } else {
            return ResultVo.fail();
        }
    }

    /**
     * 删除一篇文章
     */
    @GetMapping("/remove")
    public ResultVo remove(@RequestParam("id") Integer id) {
        final Integer result = service.removeArticleById(id);
        if (result > 0) {
            return ResultVo.success(result);
        } else {
            return ResultVo.fail();
        }
    }
}
Article
package com.frank.cache.entity;

import lombok.Data;

import java.io.Serializable;

/**
 * @author 小石潭记
 * @date 2020/6/26 11:20
 * @Description: ${todo}
 */
@Data
public class Article implements Serializable {
    private int id;
    private String title;
    private String content;
    private String author;
    private String fileName;
    private String state;
}
ResultVo
package com.frank.cache.entity;

import lombok.Data;

/**
 * @author 小石潭记
 * @date 2020/6/26 11:32
 * @Description: ${todo}
 */
@Data
public class ResultVo {
    private int code;
    private String message;
    private Object data;

    public static ResultVo success(Object object){
        ResultVo resultVo = new ResultVo();
        resultVo.setCode(200);
        resultVo.setMessage("success");
        resultVo.setData(object);
        return resultVo;
    }

    public static ResultVo fail(){
        ResultVo resultVo = new ResultVo();
        resultVo.setCode(404);
        resultVo.setMessage("fail");
        resultVo.setData(null);
        return resultVo;
    }
}
ArticleMapper
package com.frank.cache.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.frank.cache.entity.Article;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.cache.annotation.CacheConfig;

import java.util.List;

/**
 * @author 小石潭记
 * @date 2020/6/26 11:23
 * @Description: ${todo}
 */
public interface ArticleMapper extends BaseMapper<Article> {
    /**
     * 自定义sql查询
     */
    List<Article> getAllArticles();
}
ArticleRedisService
package com.frank.cache.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.frank.cache.entity.Article;
import com.frank.cache.mapper.ArticleMapper;
import com.frank.cache.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author 小石潭记
 * @date 2020/6/26 11:27
 * @Description: service层引入cache缓存
 *               使用redis的set方式设置缓存
 */
@Service
@Slf4j
public class ArticleRedisService {

    private AtomicInteger count =new AtomicInteger(0);

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 增加一篇文章 每次就进行缓存
     * @return
     */
    public Integer addArticle(Article article){
        int insert = articleMapper.insert(article);
        if (insert > 0) {
            return insert;
        }
        return null;
    }

    /**
     * 获取文章  以传入的id为键,当state为0的时候不进行缓存
     * @param id 文章id
     * @return
     */
    public Article getArticle(Integer id) {
        String key = "article_" + id;
        boolean hasKey = redisUtil.exists(key);
        if (hasKey){
            String articleStr = redisUtil.get(key);
            JSONObject jsonObject = JSONObject.parseObject(articleStr);
            Article article = jsonObject.toJavaObject(Article.class);
            log.info("从缓存redis中获取的数据:{}", article);
            return article;
        }
        try {
            //模拟耗时操作
            Thread.sleep(5000);
            Article article = articleMapper.selectById(id);
            log.info("--执行数据库查询操作"+count.incrementAndGet()+"次"+"id:"+id);
            // 将查询的结果保存至redis缓存里
            redisUtil.set(key, article);
            return article;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 自定义的sql方法
     * @return
     */
    public Object getAllArticles() {
        try {
            String key = "getAllArticles";
            boolean hasKey = redisUtil.exists(key);
            if (hasKey) {
                String str = redisUtil.get(key);
                return str;
            }
            //模拟耗时操作
            Thread.sleep(5000);
            List<Article> allArticles = articleMapper.getAllArticles();
            redisUtil.set(key, allArticles);
            return allArticles;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 通过id更新内容 清除以id作为键的缓存
     */
    public Integer update(Article article) {
        try {
            log.info("==========数据库中更新文章信息=========");
            UpdateWrapper<Article> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", 1);
            articleMapper.update(article, updateWrapper);
            String key = "article_" + article.getId();
            boolean hasKey = redisUtil.exists(key);
            if (hasKey) {
                redisUtil.remove(key);
                log.info("删除缓存中的key=========>" + key);
            }
            // 再将更新后的数据加入缓存
            redisUtil.set(key,  JSON.toJSONString(article));
            return 1;
        }catch (Exception e) {
            return 0;
        }
    }

    /**
     * 通过id移除文章
     * @param id  清除以id作为键的缓存
     * @return
     */
    public Integer removeArticleById(Integer id){
        int result = articleMapper.deleteById(id);
        log.info("执行删除操作,id:"+id);
        String key = "article_" + id;
        redisUtil.remove(key);
        return result;
    }
}
RedisUtil(set方法里面设置了过期时间30s,根据实际情况修改)
package com.frank.cache.util;

import java.io.Serializable;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

/**
 *
 * @Description: spring boot 的redis工具类
 */
@Component
public class RedisUtil {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 批量删除对应的value
     */
    public void remove(final String... keys) {
        for (String key : keys) {
            remove(key);
        }
    }

    /**
     * 批量删除key
     */
    public void removePattern(final String pattern) {
        Set<Serializable> keys = redisTemplate.keys(pattern);
        if (keys.size() > 0)
            redisTemplate.delete(keys);
    }

    /**
     * 删除对应的value
     */
    public void remove(final String key) {
        if (exists(key)) {
            redisTemplate.delete(key);
        }
    }

    /**
     * 判断缓存中是否有对应的value
     */
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 读取缓存
     */
    public String get(final String key) {
        Object result = null;
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        if (result == null) {
            return null;
        }
        return result.toString();
    }

    /**
     * 写入缓存, 并且设置了30s过期
     */
    public boolean set(final String key, Object value) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value, 30, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 写入缓存
     *
     * @param key
     * @param value
     * @return
     */
    public boolean set(final String key, Object value, Long expireTime) {
        boolean result = false;
        try {
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            operations.set(key, value);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public boolean hmset(String key, Map<String, String> value) {
        boolean result = false;
        try {
            redisTemplate.opsForHash().putAll(key, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public Map<String, String> hmget(String key) {
        Map<String, String> result = null;
        try {
            result = redisTemplate.opsForHash().entries(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

}

RedisSpringbootApplication
package com.frank.cache;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

/**
 * @author 小石潭记
 * @date 2020/6/26 12:42
 * @Description: ${todo}
 */
@SpringBootApplication
@EnableCaching
@MapperScan(basePackages = {"com.frank.cache"})
public class RedisSpringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(RedisSpringbootApplication.class, args);
    }
}

ArticleMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd">
<mapper namespace="com.frank.cache.mapper.ArticleMapper">
    <select id="getAllArticles" resultType="com.frank.cache.entity.Article">
        select * from article
    </select>
</mapper>

test:

Code download

Guess you like

Origin blog.csdn.net/qq_33371766/article/details/106975970