小蚂蚁 发表于 2021-12-25 12:11:51

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

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



一、创建springboot项目

1. 创建项目springboot_redis


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文件。

发现springboot是spring-data-redis进行实现,进入spring-data-redis配置文件,实现方式有俩种一个为jedis,另一个为lettuce。


2. 查看源码properties
引入jar包中找到autoconfigure包,打开spring-autoconfigure-metadata.properties配置文件。搜索redis相关配置。

进入RedisAutoConfiguration

redis模板和常用string类型模板

模板实现方式有俩种,一种是jedis,一种是lettuce点击进入,可以看到实现类有俩种

而jedis实现方式已经放弃


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

1. 调用默认模板
注入默认redis模板,进行调用,发现模板已经进行了封装,封装如下:

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"));
    }
}


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. 调用自定义注解

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"));
    }
}结果输出


附录
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);
            } 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;
      }
    }
}

https://blog.51cto.com/u_13501912/4836230
页: [1]
查看完整版本: #yyds干货盘点# redis | 十四、springboot整合redis