介绍

个人springdome 测试

软件架构

  • redis 基于 Lettuce 学习(springboot2.x其中使用的是Lettuce,springboot1.x系列中,其中使用的是jedis)

    a. Lettuce 和 Jedis 的定位都是Redis的client,所以他们当然可以直接连接redis server。
    b. Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接
    c. Lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,应为StatefulRedisConnection是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。

1、pom包,yml配置


 <!-- redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.6.0</version>
</dependency>
        

yml

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    password: adminroot
    username: root
    url: jdbc:mysql://localhost:3306/vue_authentication?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
  redis:
    port: 6379
    host: 127.0.0.1
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0

2、config 配置

@EnableCaching
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig {
    /**
     * 配置自定义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 serializer = new Jackson2JsonRedisSerializer(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<>(10);
        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;
    }
}

3、简单使用


    @Test
    public void contextLoads() {
        // redis存储数据
        String key = "name";
        redisTemplate.opsForValue().set(key, "yukong");
        // 获取数据
        String value = (String) redisTemplate.opsForValue().get(key);
        System.out.println("获取缓存中key为" + key + "的值为:" + value);

        User user = new User();
        user.setUsername("yukong");
        user.setSex(18);
        user.setId(1L);
        String userKey = "yukong";

        redisTemplate.opsForValue().set(userKey, user);
        User newUser = (User) redisTemplate.opsForValue().get(userKey);
        System.out.println("获取缓存中key为" + userKey + "的值为:" + newUser);

    }

4、使用缓存(概念介绍)

Spring Cache常见概念介绍
名称解释
Cache缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、ConcurrentMapCache等
CacheManager缓存管理器,管理各种缓存(cache)组件
@Cacheable主要针对方法配置,能够根据方法的请求参数对其进行缓存
@CacheEvict清空缓存
@CachePut保证方法被调用,又希望结果被缓存。与@Cacheable区别在于是否每次都调用方法,常用于更新
@EnableCaching开启基于注解的缓存
keyGenerator缓存数据时key生成策略
serialize缓存数据时value序列化策略
@CacheConfig统一配置本类的缓存注解的属性
注解(@Cacheable/@CachePut/@CacheEvict)的主要参数
名称解释
value缓存的名称,在 spring 配置文件中定义,必须指定至少一个 e.g. @Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”}
key缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 e.g. @Cacheable(value=”testcache”,key=”#id”)
condition缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存/清除缓存 e.g.@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
unless否定缓存。当条件结果为TRUE时,就不会缓存。 e.g.@Cacheable(value=”testcache”,unless=”#userName.length()>2”)
allEntries(@CacheEvict )是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 e.g. @CachEvict(value=”testcache”,allEntries=true)
beforeInvocation(@CacheEvict)是否在方法执行前就清空,缺省为 false,如果指定为 true, 则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 e.g. @CachEvict(value=”testcache”,beforeInvocation=true)

5、service层代码


@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;


    @Override
    public User saveUser(User user) {
        userMapper.save(user);
        // 返回用户信息,带id
        return user;
    }

    /**
     * @param id 主键id
     * @return
     * @CacheEvict 应用到删除数据的方法上,调用方法时会从缓存中删除对应key的数据
     * condition 与unless相反,只有表达式为真才会执行。
     */
    @CacheEvict(value = "user", key = "#root.args[0]", condition = "#result eq true")
    @Override
    public Boolean removeUser(int id) {
        // 如果删除记录不为1  则是失败
        return userMapper.deleteById(id) == 1;
    }

    /**
     * @param id 主键id
     * @return
     * @Cacheable 应用到读取数据的方法上,先从缓存中读取,如果没有再从DB获取数据,然后把数据添加到缓存中
     * key 缓存在redis中的key
     * unless 表示条件表达式成立的话不放入缓存
     */
    @Cacheable(value = "user", key = "#root.args[0]", unless = "#result eq null ")
    @Override
    public User getById(int id) {
        return userMapper.selectById(id);
    }

    /**
     * @param user 用户信息
     * @return
     * @CachePut 应用到写数据的方法上,如新增/修改方法,调用方法时会自动把相应的数据放入缓存
     */
    @CachePut(value = "user", key = "#root.args[0]", unless = "#user eq null ")
    @Override
    public User updateUser(User user) {
        userMapper.update(user);
        return user;
    }
}

6、接口测试

  @Autowired
    private UserService userService;

    @PostMapping
    public User save(@RequestBody User user) {
        return userService.saveUser(user);
    }

    @PutMapping
    public User update(@RequestBody User user) {
        return userService.updateUser(user);
    }

    @DeleteMapping(value = "/id/{id}")
    public Boolean delete(@PathVariable int id) {
        return userService.removeUser(id);
    }

    @GetMapping(value = "/id/{id}")
    public User findById(@PathVariable int id) {
        return userService.getById(id);
    }

注意版本

码云

reference

1、SpringBoot进阶教程(五十三)整合Redis之@Cacheable、@CachePut、@CacheEvict的应用

2、【SpringBoot2.0系列07】SpringBoot之redis使用(Lettuce版本)

3、不错的小知识点RedisTemplate用法详解

最后修改:2020 年 02 月 13 日
如果觉得我的文章对你有用,请随意赞赏