SpringBoot+Mybatis+Redis 实现缓存

环境版本

Mysql-8.0
springboot-2.1.6
jdk-1.8

1.新建项目

新建项目

2.采用mybatis-generator自动生成mapper,dao,entity

链接:https://www.jianshu.com/p/b519e9ef605f

3.首先实现springboot+mybatis

链接:https://www.jianshu.com/p/16f910aa4cf4

4.先安装redis数据库

Linux下和Win10下:https://www.jianshu.com/p/1299f5754d74

5.项目中配置redis

1.添加redis的properties的配置

# ==============================
# redis configurations
# ==============================
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=123456
# Redis数据库索引(默认为0)
spring.redis.database=0
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.lettuce.pool.max-active=8  
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.lettuce.pool.max-wait=-1ms
# 连接池中的最大空闲连接
spring.redis.lettuce.pool.max-idle=8  
# 连接池中的最小空闲连接
spring.redis.lettuce.pool.min-idle=0

添加依赖

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>


2.Redis Java配置(RedisConfig.java)

package com.wglvzyx.mybatisredis.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;


import java.time.Duration;
import java.util.*;

/**
 * @description redis配置  配置序列化方式以及缓存管理器
 */
@EnableCaching // 开启缓存
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig extends CachingConfigurerSupport {

    /**
     *  配置自定义redisTemplate
     *
     * @param connectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        template.setValueSerializer(jackson2JsonRedisSerializer());
        //使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(jackson2JsonRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }

    /**
     * json序列化
     * @return
     */
    @Bean
    public RedisSerializer<Object> jackson2JsonRedisSerializer() {
        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<Object>(Object.class);

        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(mapper);
        return serializer;
    }

    /**
     * 缓存管理器配置
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        // 生成一个默认配置,通过config对象即可对缓存进行自定义配置
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        // 设置缓存的默认过期时间,也是使用Duration设置
        config = config.entryTtl(Duration.ofMinutes(1))
                // 设置 key为string序列化
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                // 设置value为json序列化
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer()))
                // 不缓存空值
                .disableCachingNullValues();

        // 设置一个初始化的缓存空间set集合
        Set<String> cacheNames = new HashSet<>();
        cacheNames.add("timeGroup");
        cacheNames.add("user");

        // 对每个缓存空间应用不同的配置
        Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
        configMap.put("timeGroup", config);
        configMap.put("user", config.entryTtl(Duration.ofSeconds(120)));

        // 使用自定义的缓存配置初始化一个cacheManager
        RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory)
                // 一定要先调用该方法设置初始化的缓存名,再初始化相关的配置
                .initialCacheNames(cacheNames)
                .withInitialCacheConfigurations(configMap)
                .build();
        return cacheManager;
    }

    /**
     * 缓存的key是 包名+方法名+参数列表
     */
    @Bean
    public KeyGenerator keyGenerator() {
        return (target, method, objects) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            sb.append("::" + method.getName() + ":");
            for (Object obj : objects) {
                sb.append(obj.toString());
            }
            return sb.toString();
        };
    }

}

3.介绍缓存注解

  • 常用的缓存注解
@Cacheable – 表明对应方法的返回结果可以被缓存,首次调用后,下次就从缓存中读取结果,方法不会再被执行了。
@CachePut – 更新缓存,方法每次都会执行
@CacheEvict – 清除缓存,方法每次都会执行
...等等
因为主要的业务逻辑在服务层实现,一般会把缓存注解加在服务层的方法上。

4.缓存举例子

  • 序列化实体类Student
    implements Serializable

  • 在StudentService服务类中,给查询单个学生方法添加@Cacheable注解
    表示:方法的返回结果会被缓存到redis

//key 是学生id value 是学生这个实体
    @Cacheable(key = "#stuid", value = "Student")
    public Student SelectOneStuById(int stuid){
        return studentMapper.selectByPrimaryKey(stuid);
    }
  • 在StudentService服务类中,给更改单个学生信息方法添加@CacheEvict注解
    表示:原始数据被更新了,废弃缓存数据
    @CacheEvict(key = "#stuid", value = "Student")
    public Student updateStuName(int stuid, String stuname) {
        Student oldstu = studentMapper.selectByPrimaryKey(stuid);
        oldstu.setUsername(stuname);
        int f = studentMapper.updateByPrimaryKey(oldstu);
        return oldstu;
    }

控制器中添加俩个访问地址来测试

    // 读取学生信息,测试缓存使用:除了首次读取,接下来都应该从缓存中读取
    @RequestMapping(value="{id}")
    @ResponseBody
    public Student getStu(@PathVariable long id){
        System.out.println(id);
        Student onestu = studentService.SelectOneStuById((int) id);
        return onestu;
    }
/***************************'或者'*****************************/
    // 读取学生信息,测试缓存使用:除了首次读取,接下来都应该从缓存中读取 
//用http://localhost:8080/GetOneStu?uid=1访问

    @GetMapping(value="/GetOneStu")
    @ResponseBody
    public Student getOneStu(String uid){
        int id = Integer.parseInt(uid);
        System.out.println(id);
        Student onestu = studentService.SelectOneStuById(id);
        return onestu;
    }
/****************************************************************/
    // 更新学生信息
    @RequestMapping(value="{id}/wgname")
    @ResponseBody
    public Student UpdateStu(@PathVariable long id){
        System.out.println(id);
        String name = "ceshi";
        Student onestu = studentService.updateStuName((int) id,name);
        return onestu;
    }

5.运行测试
监控redis服务器,打开redis-cli.exe,然后使用monitor命令开始监控:


获取用户信息

修改用户信息

6.使用RedisTemplate访问redis服务器

  • 在控制层添加访问路径
  //@Resource的作用相当于@Autowired,只不过@Autowired按byType(按类型)自动注入,而@Resource默认按 byName(按名称)自动注入罢了
    @Resource(name = "redisTemplate")
    RedisTemplate<String,Object> redis;

    // 使用RedisTemplate访问redis服务器
    @RequestMapping(value="/redis", method=RequestMethod.GET, produces="application/json")
    @ResponseBody
    public String redis() throws Exception {
        // 设置键"ceshi-key=wg",值"ceshi-value=zyx"
        redis.opsForValue().set("ceshi-key=wg", "ceshi-value=zyx");
        String value = (String) redis.opsForValue().get("ceshi-key=wg");
        return value;
    }
在软件Postman中测试

redis数据库存入了指定的键值对

  • RedisTemplate常用方法
   //向redis里存入数据和设置缓存时间
    wgRedisTemplate.opsForValue().set("test", "100",60*10,TimeUnit.SECONDS);  
     
    //value做-1操作
    wgRedisTemplate.boundValueOps("test").increment(-1);  
     
    //根据key获取缓存中的value
    wgRedisTemplate.opsForValue().get("test") 
     
    //value做+1操作  
    wgRedisTemplate.boundValueOps("test").increment(1);
     
    //根据key获取过期时间  
    wgRedisTemplate.getExpire("test")
     
    //根据key获取过期时间并换算成指定单位 
    wgRedisTemplate.getExpire("test",TimeUnit.SECONDS) 
     
    //根据key删除缓存
    wgRedisTemplate.delete("test");  
     
    //检查key是否存在,返回boolean值
    wgRedisTemplate.hasKey("546545");  
     
    //向指定key中存放set集合
    wgRedisTemplate.opsForSet().add("red_123", "1","2","3");
      
    //设置过期时间
    wgRedisTemplate.expire("red_123",1000 , TimeUnit.MILLISECONDS); 
     
    //根据key查看集合中是否存在指定数据  
    wgRedisTemplate.opsForSet().isMember("red_123", "1")
     
    //根据key获取set集合
    wgRedisTemplate.opsForSet().members("red_123");

参考文章:https://www.qikegu.com/docs/2576

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容