SpringBoot整合Redis

背景

地点:长沙飞思

时间:2023/12/18~22

关键字:SpringBoot、Redis

前言

SpringBoot作为java最重要的一个框架,我们的项目都得围绕着它运行,而数据库的修改与查询又是项目中的重中之重,传统的关系型数据库已经很难满足当前互联网环境下的高并发,大数据,Redis等非关系型数据库开始崭露头角,于是如何将SpringBoot与Redis整合就是本期我们的主题。

SpringBoot与Redis

环境搭建

在实际开发中,我们使用Redis,一般是使用RedisTemplate类来操作Redis,这种方式比较灵活,在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>
</dependency>

Spring boot使用spring-boot-starter-data-redis来自动配置Lettuce和Jedis这两种redis的Java客户端。默认选用的是Lettuce。

默认使用Lettuce,改用Jedis:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
   <exclusions>
      <exclusion>
         <groupId>io.lettuce</groupId>
         <artifactId>lettuce-core</artifactId>
      </exclusion>
   </exclusions>
</dependency>
<dependency>
   <groupId>redis.clients</groupId>
   <artifactId>jedis</artifactId>
</dependency>

第二步: 添加redis配置

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

如果是jedis配置,只需要把lettice修改为jedis即可:

spring:  
 redis:
    database: 0
    host: 192.168.145.138
    port: 6379
    password: 123
    jedis:
      pool:
        min-idle: 3
        max-active: 20
        max-wait: -1ms
        max-idle: 10
    # 连接超时时间(毫秒)
    timeout: 10000ms

lettcus与jedis区别:

1. jedis连接Redis服务器是直连模式,当多线程模式下使用jedis会存在线程安全问题,解决方案可以通过配置连接池使每个连接专用,这样整体性能就大受影响。
2. lettcus基于Netty框架进行与Redis服务器连接,底层设计中采用StatefulRedisConnection。 StatefulRedisConnection自身是线程安全的,可以保障并发访问安全问题,所以一个连接可以被多线程复用。当然lettcus也支持多连接实例一起工作。

Spring Boot会根据application.yml的配置,自动生成两个bean: RedisTemplate<Object,Object>和StringRedisTemplate。

查看RedisAutoConfiguration源码:

RedisTemplate的key和value默认使用的序列化是: JdkSerializationRedisSerializer

StringRedisTemplate的key和value默认使用的序列化是:StringRedisSerializer

所以我们可以自定义创建RedisTemplate和StringRedisTemplate

@Configuration
@EnableCaching //开启缓存
public class RedisConfig extends CachingConfigurerSupport {

    /**
     * retemplate相关配置
     *
     * @param factory
     * @return
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {

        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 配置连接工厂
        template.setConnectionFactory(factory);

        // 值采用json序列化
        template.setValueSerializer(valueSerializer());
        //使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());

        // 设置hash key 和value序列化模式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(valueSerializer());
        template.afterPropertiesSet();

        return template;
    }
    /**
      * 往容器中添加RedisCacheManager容器,并设置序列化方式
      * @param redisConnectionFactory
      * @return
   */
  @Bean
  public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
    RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
    RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()));
    redisCacheConfiguration.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
    return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
  }

  private RedisSerializer valueSerializer(){
      //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
      Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);

      ObjectMapper om = new ObjectMapper();
      // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
      om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
      // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
      om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
      jacksonSeial.setObjectMapper(om);
      return jacksonSeial;
  }

}

使用RedisTemplate来操作Redis

Spring封装了RedisTemplate/StringRedisTemplate对象来进行对Redis的各种操作,它支持所有的Redis原生的api.RedisTemplate/StringRedisTemplate位于Spring-data-redis包下.

RedisTemplate/StringRedisTemplate中定义了对redis的5种数据结构的操作:

  • opsForValue() 操作字符串

  • opsForHash() 操作hash

  • opsForList() 操作list

  • opsForSet() 操作set

  • opsForZSet() 操作ZSet

注意: 

RedisTemplate与StringRedisTemplate之间不能混用,他们是有区别的.

    1.两者数据各自存,各自取,数据不互通。

  • RedisTemplate不能取StringRedisTemplate存入的数据。

  • StringRedisTemplate不能取RedisTemplate存入的数据

      2.序列化策略不同。

  • RedisTemplate默认采用JDK的序列化策略

  • StringRedisTemplate默认采用String的序列化策略

如果你需要缓存的是字符串,那么你就使用StringRedisTemplate即可。但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象,那么使用RedisTemplate是更好的选择

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    //事务控制
    @Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
    public Page<User> queryByPage(Integer current, Integer size, UserVO userVO) {
        Page<User> page = new Page<>(current,size);
        //排序 根据年龄升序排序
        List<OrderItem> orderItems = new ArrayList<>();
        orderItems.add(OrderItem.asc("age"));
        page.setOrders(orderItems);
        StringBuffer redisKey = new StringBuffer("page_");
        redisKey.append(current);
        //设置条件
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        if(userVO != null){
            if(!StringUtils.isEmpty(userVO.getName())){
                queryWrapper.like("name",userVO.getName());
                redisKey.append("_name_"+userVO.getName());
            }
            if(!StringUtils.isEmpty(userVO.getGender())){
                queryWrapper.eq("gender",userVO.getGender());
                redisKey.append("_gender_"+userVO.getGender());
            }
            if(Objects.nonNull(userVO.getStartAge())){
                queryWrapper.gt("age",userVO.getStartAge());
                redisKey.append("_age1_"+userVO.getStartAge());
            }
            if(Objects.nonNull(userVO.getEndAge())){
                queryWrapper.lt("age",userVO.getEndAge());
                redisKey.append("_age2_"+userVO.getEndAge());
            }
        }
        if(redisTemplate.hasKey(redisKey.toString())){
            return (Page<User>)redisTemplate.opsForValue().get(redisKey.toString());
        }
        userMapper.selectPage(page,queryWrapper);
        redisTemplate.opsForValue().set(redisKey.toString(),page,1,TimeUnit.MINUTES);
        return page;
    }
}

总结

赠人玫瑰,手有余香

  • 26
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值