一篇掌握SpringBoot+SpringCache+Redis超详细实例

1、创建maven项目

2、pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>springWithRedis</artifactId>
    <version>1.0-SNAPSHOT</version><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>8</source><target>8</target></configuration></plugin></plugins></build>

    <dependencies>

        <!-- lombok依赖 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.18</version>
        </dependency>

        <!-- spring集成redis依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.2.8.RELEASE</version>
        </dependency>

        <!-- spring依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.2.8.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
            <version>2.2.8.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.2.8.RELEASE</version>
            <scope>test</scope>
        </dependency>

    </dependencies>
</project>

2、application.properties 配置文件

# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=**********

#配置缓存相关
cache.default.expire-time=20000
cache.user.expire-time=1800
cache.user.name=suiyiqi

3、实体类

package com.cache.redis.entity;

import lombok.Data;
import java.io.Serializable;

/**
 * @author 一抹余阳
 */
@Data
// 对象要序列化,不然可能会出现乱码
public class UserInfo implements Serializable {

    private String id;

    private String nickName;

}

4、service

package com.cache.redis.service;

import com.cache.redis.entity.UserInfo;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import java.util.List;

/**
 * @author 一抹余阳
 */
// @CacheConfig:定义公共设置
@CacheConfig(cacheNames="userInfo2")
public interface UserInfoService {

    // 1、@Cacheable:定义缓存,用于触发缓存.
    // 该注解用于标注于方法之上用于标识该方法的返回结果需要被缓存起来,
    // 标注于类之上标识该类中所有方法均需要将结果缓存起来。
    // 该注解标注的方法每次被调用前都会触发缓存校验,
    // 校验指定参数的缓存是否已存在(已发生过相同参数的调用),
    // 若存在,直接返回缓存结果,否则执行方法内容,最后将方法执行结果保存到缓存中。
    // 2、key:用于指定当前方法的缓存保存时的键的组合方式,
    // 默认的情况下使用所有的参数组合而成,这样可以有效区分不同参数的缓存。
    // 当然我们也可以手动指定,指定的方法是使用SPEL表达式。
    // #root.methodName -> 即为用当前方法名称做为key
    // #id -> 即为用入参名称id作为key
    // #userInfo.id -> 即为用UserInfo对象的id属性作为key
    // 3、 @Cacheable(cacheNames = "userInfo",key = "#id"),cacheNames也可以单独指定
    // 4、键值对缓存key,就是说redis缓存的时候key的生成时如下格式:value::key 或 cacheNames::key
    // 例如,指定value或cacheNames为 userInfo2,key为1,
    // 即 @Cacheable(value="userInfo2",key="1") 或 @Cacheable(cacheNames = "userInfo",key = "#id")
    // 生成的缓存key值为 userInfo2::1
    @Cacheable(key = "#root.methodName")
    List<UserInfo> findAll();

    // @CachePut:定义更新缓存,触发缓存更新
    @Cacheable(key = "#id")
    UserInfo findById(String id);

    // @CachePut:该注解用于更新缓存,无论结果是否已经缓存,
    // 都会在方法执行结束插入缓存,相当于更新缓存,一般用于更新方法之上。
    @CachePut(key = "#userInfo.id")
    UserInfo saveUserInfo(UserInfo userInfo);

    // @CacheEvict:该注解主要用于删除缓存操作
    // allEntries=true:删除所有缓存
    // @CacheEvict(key = "#id") 删除id为某值的缓存
    @CacheEvict(allEntries=true)
    void delUserInfo(String id);

    // 扩展:condition属性是用来指定判断条件从而确定是否生成缓存
    // @Cacheable(value = "userInfo2",key = "#id",condition="#id%2 == 0")
    // 如果id%2 == 0判断条件成立的话,将会生成redis缓存,即返回true时生成Redis缓存,
    // 如果EL表达式返回false的话则不生成缓存


}

5、service实现类

package com.cache.redis.service.impl;

import com.cache.redis.entity.UserInfo;
import com.cache.redis.service.UserInfoService;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 一抹余阳
 * 全部直接模拟数据库操作,省掉dao层,如果需要可以自行添加
 */
@Service
public class UserInfoServiceImpl implements UserInfoService {

    @Override
    public List<UserInfo> findAll() {
        System.out.println("查了全部数据。。。");
        UserInfo userInfo = new UserInfo();
        userInfo.setId("200");
        userInfo.setNickName("搬砖小能手");
        UserInfo userInfo2 = new UserInfo();
        userInfo2.setId("300");
        userInfo2.setNickName("我是谁");
        List<UserInfo> userInfoList = new ArrayList<>();
        userInfoList.add(userInfo);
        userInfoList.add(userInfo2);
        return userInfoList;
    }

    @Override
    public UserInfo findById(String id) {
        System.out.println("查了一次数据库。。。");
        UserInfo userInfo = new UserInfo();
        if("100".equals(id)){
            userInfo.setNickName("呵呵");
            userInfo.setId("100");
        }else{
            userInfo.setNickName("哈哈");
            userInfo.setId("101");
        }
        return userInfo;
    }

    @Override
    public UserInfo saveUserInfo(UserInfo userInfo) {
        System.out.println("新增或者修改了一次数据。。。");
        return userInfo;
    }

    @Override
    public void delUserInfo(String id) {
        System.out.println("删除了一个数据。。。");
    }
}

6、redisconfig类

package com.cache.redis.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
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.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author 一抹余阳
 * @create 2020-09-25 10:25
 */
@Configuration      //@Configuration:项目启动配置注解
@EnableCaching      //@EnableCaching:开启缓存功能
public class RedisConfig {

    //@ 读取 application.properties 配置的值
    @Value("${cache.default.expire-time}")
    private int defaultExpireTime;
    @Value("${cache.user.expire-time}")
    private int userCacheExpireTime;
    @Value("${cache.user.name}")
    private String userCacheName;

    /**
     * 缓存管理器
     * @param lettuceConnectionFactory
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory lettuceConnectionFactory) {
        RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig();
        // 设置缓存管理器管理的缓存的默认过期时间
        defaultCacheConfig = defaultCacheConfig.entryTtl(Duration.ofSeconds(defaultExpireTime))
                // 设置 key为string序列化
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                // 设置value为json序列化
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
                // 不缓存空值
                .disableCachingNullValues();

        Set<String> cacheNames = new HashSet<>();
        cacheNames.add(userCacheName);

        // 将需要不同过期时间 cacheNames 配置
        // 对每个缓存空间应用不同的配置,如果所有cacheNames的过期时间都一直,则则不需要特殊配置
        Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
        configMap.put(userCacheName, defaultCacheConfig.entryTtl(Duration.ofSeconds(userCacheExpireTime)));

        RedisCacheManager cacheManager = RedisCacheManager.builder(lettuceConnectionFactory)
                .cacheDefaults(defaultCacheConfig)
                .initialCacheNames(cacheNames)
                .withInitialCacheConfigurations(configMap)
                .build();
        return cacheManager;
    }
}

7、启动类

package com.cache.redis;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;

/**
 * @author 一抹余阳
 */

@SpringBootApplication
@PropertySources(value = {@PropertySource(value = {"classpath:application.properties"}, encoding = "utf-8")
})
@Slf4j
public class App {

    /**
     * 启动方法
     * @param args
     */
    public static void main(String[] args) {
        log.info("ApiMain begin...");
        try {
            SpringApplication.run(App.class, args);
            log.info("App run sucessful!");
        } catch (Throwable throwable) {
            log.error("App run error!error msg is {}", throwable.getMessage(), throwable);
        }
    }
}

8、测试类

import com.cache.redis.App;
import com.cache.redis.entity.UserInfo;
import com.cache.redis.service.UserInfoService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import java.util.List;

/**
 *  @author 一抹余阳
 *  redis缓存测试
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
public class CacheTest {

    @Resource
    UserInfoService userInfoService;

    @Test
    public void findAll(){
        // 测试缓存:
        // 第一次查询:没有缓存会先模拟查询数据库 打印 查了全部数据。。。
        // 然后打印查到的数据
        // 第二次查询:缓存里有数据,会直接打印缓存的数据
        List<UserInfo> all = userInfoService.findAll();
        System.out.println(all);
    }

    @Test
    public void queryUserInfo(){
        // 第一次查询:没有缓存数据会先模拟查询数据库 打印 查了一次数据库。。。
        // 然后打印模拟查询的数据
        UserInfo user = userInfoService.findById("100");
        System.out.println(user);
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 第二查询:缓存中有数据,会直接从缓存中查询到数据直接打印,不去模拟数据库查询操作
        UserInfo user2 = userInfoService.findById("100");
        System.out.println(user2);
    }

    @Test
    public void delUserINfo(){
        // 如 queryUserInfo() ,缓存中有数据则直接返回缓存中数据,没有模拟查询数据库
        UserInfo user = userInfoService.findById("100");
        System.out.println(user);
        // 删除掉缓存中 id为100 的数据
        userInfoService.delUserInfo("100");
        // 再次查询则还需要模拟数据库查询操作
        UserInfo user2 = userInfoService.findById("100");
        System.out.println(user2);
    }

    @Test
    public void saveOrUpdateUserInfo(){
        // 不论缓存中有没有数据,都去模拟数据库操作,更新userInfo.id为100的到缓存
        UserInfo userInfo = new UserInfo();
        userInfo.setNickName("嘎嘎");
        userInfo.setId("100");
        UserInfo userInfo2 = userInfoService.saveUserInfo(userInfo);
        System.out.println("修改后的数据" + userInfo2);
    }


}

9、项目架构截图

jiegou

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值