跳至主要內容

SpringBoot整合Redis

晨光-向大约 4 分钟RedisRedis数据库非关系型数据库缓存

SpringBoot整合Redis

SpringBootopen in new window 操作数据:spring-data jpa. jdbc. mongodb. redis!

SpringDataopen in new window 也是和 SpringBoot 齐名的项目!

说明: 在 SpringBoot2.x 之后,客户端原来使用的jedis 被替换为了 lettuce?

jedis : 采用的直连多个线程操作的话,是不安全的,如果想要避免不安全的,使用 jedis pool 连接池! 更像 BIO 模式.

lettuce : 采用netty,实例可以再多个线程中进行共享,不存在线程不安全的情况!可以减少线程数据了,更像 NIO 模式.

1. 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

springboot版本 2.x使用的是 lettce

  • 上边集成boot的依赖所包含的核心包
<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <version>2.2.5.RELEASE</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>2.2.5.RELEASE</version>
    <scope>compile</scope>
    <exclusions>
      <exclusion>
        <artifactId>jcl-over-slf4j</artifactId>
        <groupId>org.slf4j</groupId>
      </exclusion>
    </exclusions>
  </dependency>
  <dependency>
    <groupId>io.lettuce</groupId>
    <artifactId>lettuce-core</artifactId>
    <version>5.2.2.RELEASE</version>
    <scope>compile</scope>
  </dependency>
</dependencies>

当在配置文件application.properties配置 lettuce 时,启动项目出现

Caused by: java.lang.ClassNotFoundException: org.apache.commons.pool2.impl.GenericObjectPoolConfig
	at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	... 93 more

解决: pxm.xml配置

<!--redis客户端Lettuce 数据库连接池依赖 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

2. 配置

2.1 redis配置类[源码]

  • RedisAutoConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {

   // RedisTemplate
   @Bean
   // 我们可以自己定义一个 redisTemplate来替换这个默认的!
   @ConditionalOnMissingBean(name = "redisTemplate")
   public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
         throws UnknownHostException {
       // 默认的 RedisTemplate 没有过多的设置,redis 对象都是需要序列化!
       // 两个泛型都是 Object, Object 的类型,我们后使用需要强制转换 <String, Object>
      RedisTemplate<Object, Object> template = new RedisTemplate<>();
      template.setConnectionFactory(redisConnectionFactory);
      return template;
   }

    // StringRedisTemplate
   @Bean
   // 由于 String 是redis中最常使用的类型,所以说单独提出来了一 个bean!
   @ConditionalOnMissingBean
   public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
         throws UnknownHostException {
      StringRedisTemplate template = new StringRedisTemplate();
      template.setConnectionFactory(redisConnectionFactory);
      return template;
   }

}

@ConditionalOnMissingBean: 当这个Bean不存在式,这个类生效

  • RedisProperties: redis默认配置
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {

   private int database = 0;

   private String url;

   private String host = "localhost";

   private String password;

   private int port = 6379;

   private boolean ssl;

   private Duration timeout;

   private String clientName;

   private Sentinel sentinel;

   private Cluster cluster;

}

2.2 配置文件

# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis数据库索引(默认为0)
spring.redis.database=0
#  Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接超时时间
spring.redis.timeout=10000ms

# 这里使用 lettuce
# 连接池最大连接数
spring.redis.lettuce.pool.max-active=1000 
# 连接池最大阻塞等待时间
spring.redis.lettuce.pool.max-wait=-1ms
# 连接池最大空闲连接
spring.redis.lettuce.pool.max-idle=10 
#连接池最小空闲连接
spring.redis.lettuce.pool.min-idle=5

此处使用 .properties 形式配置

3 测试

3.1 乱码

	@Resource
    private RedisTemplate redisTemplate;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Test
    void contextLoads() {
        redisTemplate.opsForValue().set("key01", "Hello Redis !");
        stringRedisTemplate.opsForValue().set("key02", "Hello Redis !");
    }
127.0.0.1:6379> keys *
1) "key02" 
2) "\xac\xed\x00\x05t\x00\x05key01"

redisTemplate: 出现中文乱码

3.2 对象保存需要序列化

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private String name;
    private Integer age;

}
// User实体类,未序列化
User user = new User("chggx", 3);
redisTemplate.opsForValue().set("user",user);

结果:

解决: 在 User中添加序列化 implements Serializable

127.0.0.1:6379> keys *
1) "\xac\xed\x00\x05t\x00\x04user"

4. redis序列化配置

  • RedisTemplate

4.1 自定义redis配置类

@Configuration
public class RedisConfig {

    /**
     * Redis连接工厂
     */
    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    /**
     * String 的序列化
     *
     * @return
     */
    @Bean
    public RedisSerializer<String> stringRedisSerializer() {
        return new StringRedisSerializer();
    }

    /**
     * Jackson2JsonRedisSerializer序列化
     *
     * @return
     */
    @Bean
    public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        return jackson2JsonRedisSerializer;
    }

    /**
     * RedisTemplate
     *
     * @return
     */
    @Bean
    public RedisTemplate<Object, Object> redisTemplate() {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();

        // Redis连接工厂
        template.setConnectionFactory(redisConnectionFactory);

        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer());
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer());
        // value序列化方式采用
        template.setValueSerializer(jackson2JsonRedisSerializer());
        // hash的value序列化方式采用
        template.setHashValueSerializer(jackson2JsonRedisSerializer());
        template.afterPropertiesSet();
        // 开启事务支持
        template.setEnableTransactionSupport(true);
        return template;
    }

    /**
     * StringRedisTemplate
     *
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        // Redis连接工厂
        template.setConnectionFactory(redisConnectionFactory);

        // 开启事务支持
        template.setEnableTransactionSupport(true);
        return template;
    }
  • 3.2 中结果,经过redis json序列化
127.0.0.1:6379> keys *
1) "user"
127.0.0.1:6379> get user
"[\"com.chggx.pojo.User\",{\"name\":\"chggx\",\"age\":3}]"

4.2 自定义redis工具类

自定义Redis配置类

链接:https://pan.baidu.com/s/1mVAi1-yG7fA2Y-hTwEzp5gopen in new window 提取码:fp92

  • 测试
/**
 * 自定义缓存类
 */
@Autowired
private RedisUtil redisUtil;

 @Test
void test03(){
    // 设置
    redisUtil.set("name","chggx");
    // 获取
    System.out.println(redisUtil.get("name"));
}