为什么要用缓存?这里不做过多解释,不管是移动端还是前端,我们都有接触过!Redis,是一个轻量级的key-value数据库,就类似于安卓端的SP,或者前端的localStorage,就是把要缓存的数据放入键值对,用的时候即可通过key取出value,直接缓存获取,从而不再需要再次调用接口或者查询数据库获取,这样理解,你就会觉得简单多了!

项目下载地址:

GitHub:https://github.com/baiyuliang/SpringBoot

pom.xml引入:

<!--redis-->
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
     <version>2.3.4.RELEASE</version>
 </dependency>

application.yml添加redis配置:

spring:
  redis:
    host: 39.xxx.x.xx
    port: 6379
    database: 1                # redis16库中的哪一库,默认0
    client-name: redis
    password: 123456
    timeout: 3000              # 连接超时时间(毫秒)
    jedis.pool.max-active: 8   #redis的连接池最大连接数
    jedis.pool.max-idle: 8     #redis的连接池中最大连接空闲数
    jedis.pool.max-wait: -1    #redis的连接池中最大等待时间,-1,表示没有限制
    jedis.pool.min-idle: 0     #redis的连接池中最小连接空闲数

创建RedisConfig:

package com.byl.springboottest.config;

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.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
        template.setDefaultSerializer(serializer);
        return template;
    }

    @Bean
    public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofDays(1))
                .disableCachingNullValues()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        return RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(cacheConfiguration).build();
    }

}

开始测试:

1.启用缓存@EnableCaching:Application入口:

@EnableCaching//启用缓存
@SpringBootApplication
public class SpringboottestApplication {

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

}

2.在Service的某方法上添加注解@Cacheable:

@Service
public class UserServiceImpl implements UserService {

    @Resource
    UserRepository userRepository;

    @Cacheable(cacheNames = "user", condition = "#id>0", unless = "#result==null")
    @Override
    public User getUserById(Integer id) {
        return userRepository.getOne(id);
    }

    @Override
    public User getUserByName(String username) {
        return userRepository.findByUserName(username);
    }
}

cacheNames 缓存名,condition 缓存条件(只有id>0的才缓存),unless也是缓存条件,但他表示的是非关系,也即时,满足条件了不缓存!

运行项目,浏览器输入:http://localhost:8080/byl/user/2,来测试对应方法的缓存情况:

第一次运行结果:

springboot整合redisCluster 读写分离 springboot整合redis缓存_缓存


控制台:

springboot整合redisCluster 读写分离 springboot整合redis缓存_缓存_02


表明第一次是从数据库查询的无误!查看Redis数据库:

springboot整合redisCluster 读写分离 springboot整合redis缓存_spring_03


缓存成功!我换一个浏览器,再次运行:

springboot整合redisCluster 读写分离 springboot整合redis缓存_spring_04


此时控制台并没有打印任何Sql数据,表明Redis已经整合成功!

当需要更新缓存时,我们可以在某一方法上加上@CachePut,删除缓存则用@CacheEvict!

在使用@Cacheable时要先声明cacheNames,可以这么理解,就是给你的缓存信息划分模块,与其他缓存信息互不影响,你可以把同一类业务划分到统一模块,比如例子中的user,缓存到Redis后即可在user下查询相关信息:

springboot整合redisCluster 读写分离 springboot整合redis缓存_spring_05


指定其它名称,就会生成对应的“文件夹”!

user::2,user是自动添加的字段,2就是key,因为如果我们不指定key,那么缓存会自动将参数值作为key键存入,我们可以用keyGenerator属性自定义key生成机制,但要注意的是,存入的key值要有一定的规律,那么你在更新或删除缓存时,才能准确的通过对应的key操作缓存数据!

以下是一个自定义keyGenerator的例子:

@Configuration
public class MyCacheConfig {

    @Bean("myKeyGenerator")
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object o, Method method, Object... objects) {
                return method.getName() + "[" + Arrays.asList(objects).toString() + "]";
            }
        };
    }
}

将方法名和参数作为key!

引用该keyGenerator:

@Cacheable(cacheNames = "user", condition = "#id>0", unless = "#result==null" ,keyGenerator = "myKeyGenerator")

如果我们直接在方法上声明@Cacheable,会默认把方法返回结果给缓存起来,而在实际开发中,我们在Service层中,方法的返回结果往往带有固定格式的数据模型,如:

{
	code:1,
	msg:"获取列表成功",
    data:{
		total:1,
		list:[{
		...
		}]
    }
}

这可能并不符合我们的实际需求,因为我们只想对从数据库查出来的数据进行缓存,而不想对业务层返回的数据进行缓存,此时,我们就可以直接用代码的方式进行缓存数据存取了:

@Resource
    RedisCacheManager redisCacheManager;//缓存管理器

    //    @Cacheable(cacheNames = "user",condition = "#id>0", unless = "#result==null")
    @Override
    public User getUserById(Integer id) {
        User user;
        Cache cache = redisCacheManager.getCache("user");//cacheNames
        if (cache.get("getUserById" + id) != null) {
            user = (User) cache.get("getUserById" + id).get();//通过key获取value
            if (user != null) {
                System.out.println("从缓存中获取到结果>>" + user.getNickName());
                return user;
            }
        }
        user = userRepository.findById(id).get();
        cache.put("getUserById" + id, user);//缓存数据
        return user;
    }

我们先清空redis数据库,然后运行项目,浏览器输入:http://localhost:8080/byl/user/2

springboot整合redisCluster 读写分离 springboot整合redis缓存_缓存_06


查看redis数据库:

springboot整合redisCluster 读写分离 springboot整合redis缓存_缓存_07


再次刷新浏览器:

springboot整合redisCluster 读写分离 springboot整合redis缓存_redis_08


当然,cache还有n多种方法,在合适的时候选择使用:

springboot整合redisCluster 读写分离 springboot整合redis缓存_redis_09