评论

收藏

[NoSQL] #yyds干货盘点# redis | 十四、springboot整合redis

数据库 数据库 发布于:2021-12-25 12:11 | 阅读数:444 | 评论:0

公众号:雨中散步撒哈拉
文章同步公众号,共同学习进步
个人网站:​​https://liudongdong.top​​
文章来源:​​https://liudongdong.top/archives/redisshi-si-springboot-zheng-he-redis​​



一、创建springboot项目

1. 创建项目springboot_redis
DSC0000.png

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.4</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <groupId>com.example</groupId>
  <artifactId>springboot-redis</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>springboot-redis</name>
  <description>Demo project for Spring Boot</description>
  <properties>
    <java.version>1.8</java.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <scope>runtime</scope>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-configuration-processor</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <excludes>
            <exclude>
              <groupId>org.projectlombok</groupId>
              <artifactId>lombok</artifactId>
            </exclude>
          </excludes>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
3. 创建配置文件
spring.redis.host=127.0.0.1
spring.redis.port=6379
二、源码探究
基于spring-data-redis,并且没有使用 jedis,SpringBoot 2.x 之后,原来使用的 jedis 被替换为了 lettuce。

  • jedis :采用直接连接方式,多个线程进行操作时是不安全的 ( 可能会有诸如忘记关闭连接导致开销增大等因素 ),因此可以使用 jedisPool 进行管理
  • lettuce:底层代用 netty,实例可以在多个线程中进行共享,不存在线程不安全的情况,同时高效

1. 查看源码pom文件
pom文件,ctrl+点击spring-boot-starter-data-redis,跳转到具体底层pom文件。
DSC0001.png
发现springboot是spring-data-redis进行实现,进入spring-data-redis配置文件,实现方式有俩种一个为jedis,另一个为lettuce。
DSC0002.png

2. 查看源码properties
引入jar包中找到autoconfigure包,打开spring-autoconfigure-metadata.properties配置文件。搜索redis相关配置。
DSC0003.png
进入RedisAutoConfiguration
DSC0004.png
redis模板和常用string类型模板
DSC0005.png
模板实现方式有俩种,一种是jedis,一种是lettuce点击进入,可以看到实现类有俩种
DSC0006.png DSC0007.png
而jedis实现方式已经放弃
DSC0008.png

三、调用redis模板,进行操作

1. 调用默认模板
注入默认redis模板,进行调用,发现模板已经进行了封装,封装如下:
DSC0009.png
package com.example;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
@SpringBootTest
class SpringbootRedisApplicationTests {
  @Autowired
  private RedisTemplate redisTemplate;
  @Test
  void contextLoads() {
    ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
    valueOperations.set("hello", "world");
    System.out.println(valueOperations.get("hello"));
  }
}
DSC00010.png

2. 调用自定义模板
1. 自定义模板
package com.example.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.StringRedisSerializer;
import java.net.UnknownHostException;
@Configuration
public class RedisConfig {
  @Bean
  public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
      throws UnknownHostException {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(redisConnectionFactory);
    //JSON 序列化配置
    Jackson2JsonRedisSerializer jacksonSerializer = new Jackson2JsonRedisSerializer(Object.class);
    //配置默认序列化方式,Object.class 表示可以序列化所有对象
    template.setDefaultSerializer(jacksonSerializer);
    //使用 om 进行进一步配置
    ObjectMapper om = new ObjectMapper();
    //配置所有字段都可以被序列化,而不仅仅是 public (默认就是全都序列化的)
    om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    //用于指定序列化的实际类型是否符合要求,这里的要求非 final 修饰的类
    om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
    jacksonSerializer.setObjectMapper(om);
    //String 序列化
    StringRedisSerializer stringSerializer = new StringRedisSerializer();
    //对于源码中的两种 key 使用 string 方式序列化
    template.setKeySerializer(stringSerializer);
    template.setHashKeySerializer(stringSerializer);
    //对于源码中的两种 value 使用 json 方式序列化
    template.setValueSerializer(jacksonSerializer);
    template.setHashValueSerializer(jacksonSerializer);
    return template;
  }
}
2. 调用自定义注解
DSC00011.png
package com.example;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
@SpringBootTest
class SpringbootRedisApplicationTests {
  @Autowired
  @Qualifier("redisTemplate")
  private RedisTemplate redisTemplate;
  @Test
  void contextLoads() {
    ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
    valueOperations.set("hello", "世界你好");
    System.out.println(valueOperations.get("hello"));
  }
}

四、工具类
package com.example;
import com.example.config.RedisConfig;
import com.example.util.RedisUtil;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
@SpringBootTest
class SpringbootRedisApplicationTests {
  @Autowired
  @Qualifier("redisTemplate")
  private RedisTemplate redisTemplate;
  @Autowired
  RedisUtil redisUtil;
  @Test
  void contextLoads() {
    ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
    valueOperations.set("hello", "世界你好");
    System.out.println(valueOperations.get("hello"));
  }
  @Test
  void utilTest() {
    redisUtil.set("utilTest", "测试");
    System.out.println(redisUtil.get("utilTest"));
  }
}
结果输出
DSC00012.png

附录
RedisUtil工具类
package com.example.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Component
public final class RedisUtil {
  @Autowired
  private RedisTemplate<String, Object> redisTemplate;
// =============================common============================
  /**
   * 指定缓存失效时间
   *
   * @param key  键
   * @param time 时间(秒)
   */
  public boolean expire(String key, long time) {
    try {
      if (time > 0) {
        redisTemplate.expire(key, time, TimeUnit.SECONDS);
      }
      return true;
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }
  }
  /**
   * 根据key 获取过期时间
   *
   * @param key 键 不能为null
   * @return 时间(秒) 返回0代表为永久有效
   */
  public long getExpire(String key) {
    return redisTemplate.getExpire(key, TimeUnit.SECONDS);
  }
  /**
   * 判断key是否存在
   *
   * @param key 键
   * @return true 存在 false不存在
   */
  public boolean hasKey(String key) {
    try {
      return redisTemplate.hasKey(key);
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }
  }
  /**
   * 删除缓存
   *
   * @param key 可以传一个值 或多个
   */
  @SuppressWarnings("unchecked")
  public void del(String... key) {
    if (key != null && key.length > 0) {
      if (key.length == 1) {
        redisTemplate.delete(key[0]);
      } else {
        redisTemplate.delete(String.valueOf(CollectionUtils.arrayToList(key)));
      }
    }
  }
// ============================String=============================
  /**
   * 普通缓存获取
   *
   * @param key 键
   * @return 值
   */
  public Object get(String key) {
    return key == null ? null : redisTemplate.opsForValue().get(key);
  }
  /**
   * 普通缓存放入
   *
   * @param key   键
   * @param value 值
   * @return true成功 false失败
   */
  public boolean set(String key, Object value) {
    try {
      redisTemplate.opsForValue().set(key, value);
      return true;
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }
  }
  /**
   * 普通缓存放入并设置时间
   *
   * @param key   键
   * @param value 值
   * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
   * @return true成功 false 失败
   */
  public boolean set(String key, Object value, long time) {
    try {
      if (time > 0) {
        redisTemplate.opsForValue().set(key, value, time,
            TimeUnit.SECONDS);
      } else {
        set(key, value);
      }
      return true;
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }
  }
  /**
   * 递增
   *
   * @param key   键
   * @param delta 要增加几(大于0)
   */
  public long incr(String key, long delta) {
    if (delta < 0) {
      throw new RuntimeException("递增因子必须大于0");
    }
    return redisTemplate.opsForValue().increment(key, delta);
  }
  /**
   * 递减
   *
   * @param key   键
   * @param delta 要减少几(小于0)
   */
  public long decr(String key, long delta) {
    if (delta < 0) {
      throw new RuntimeException("递减因子必须大于0");
    }
    return redisTemplate.opsForValue().increment(key, -delta);
  }
// ================================Map=================================
  /**
   * HashGet
   *
   * @param key  键 不能为null
   * @param item 项 不能为null
   */
  public Object hget(String key, String item) {
    return redisTemplate.opsForHash().get(key, item);
  }
  /**
   * 获取hashKey对应的所有键值
   *
   * @param key 键
   * @return 对应的多个键值
   */
  public Map<Object, Object> hmget(String key) {
    return redisTemplate.opsForHash().entries(key);
  }
  /**
   * HashSet
   *
   * @param key 键
   * @param map 对应多个键值
   */
  public boolean hmset(String key, Map<String, Object> map) {
    try {
      redisTemplate.opsForHash().putAll(key, map);
      return true;
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }
  }
  /**
   * HashSet 并设置时间
   *
   * @param key  键
   * @param map  对应多个键值
   * @param time 时间(秒)
   * @return true成功 false失败
   */
  public boolean hmset(String key, Map<String, Object> map, long time) {
    try {
      redisTemplate.opsForHash().putAll(key, map);
      if (time > 0) {
        expire(key, time);
      }
      return true;
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }
  }
  /**
   * 向一张hash表中放入数据,如果不存在将创建
   *
   * @param key   键
   * @param item  项
   * @param value 值
   * @return true 成功 false失败
   */
  public boolean hset(String key, String item, Object value) {
    try {
      redisTemplate.opsForHash().put(key, item, value);
      return true;
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }
  }
  /**
   * 向一张hash表中放入数据,如果不存在将创建
   *
   * @param key   键
   * @param item  项
   * @param value 值
   * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
   * @return true 成功 false失败
   */
  public boolean hset(String key, String item, Object value, long time) {
    try {
      redisTemplate.opsForHash().put(key, item, value);
      if (time > 0) {
        expire(key, time);
      }
      return true;
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }
  }
  /**
   * 删除hash表中的值
   *
   * @param key  键 不能为null
   * @param item 项 可以使多个 不能为null
   */
  public void hdel(String key, Object... item) {
    redisTemplate.opsForHash().delete(key, item);
  }
  /**
   * 判断hash表中是否有该项的值
   *
   * @param key  键 不能为null
   * @param item 项 不能为null
   * @return true 存在 false不存在
   */
  public boolean hHasKey(String key, String item) {
    return redisTemplate.opsForHash().hasKey(key, item);
  }
  /**
   * hash递增 如果不存在,就会创建一个 并把新增后的值返回
   *
   * @param key  键
   * @param item 项
   * @param by   要增加几(大于0)
   */
  public double hincr(String key, String item, double by) {
    return redisTemplate.opsForHash().increment(key, item, by);
  }
  /**
   * hash递减
   *
   * @param key  键
   * @param item 项
   * @param by   要减少记(小于0)
   */
  public double hdecr(String key, String item, double by) {
    return redisTemplate.opsForHash().increment(key, item, -by);
  }
// ============================set=============================
  /**
   * 根据key获取Set中的所有值
   *
   * @param key 键
   */
  public Set<Object> sGet(String key) {
    try {
      return redisTemplate.opsForSet().members(key);
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }
  }
}

关注下面的标签,发现更多相似文章