> 文档中心 > SpringBoot整合Redis

SpringBoot整合Redis

在SpringBoot2.x后,原来使用的jedis被替换为lettuce

jedis:底层采用的直连,多线程操作不安全,解决方案是使用jedis pool连接池 bio模式

lettuce:底层采用的netty,实例可以在多个线程中进行共享,不存在线程不安全的情况 可以减少线程数量 nio模式

pom.xml

    4.0.0    com.chen    redis02-springboot    0.0.1-SNAPSHOT    redis02-springboot    Demo project for Spring Boot     1.8 UTF-8 UTF-8 2.3.7.RELEASE              org.springframework.boot     spring-boot-starter-data-redis       org.springframework.boot     spring-boot-starter-web       org.springframework.boot     spring-boot-devtools     runtime     true       org.springframework.boot     spring-boot-configuration-processor     true       org.projectlombok     lombok     true       org.springframework.boot     spring-boot-starter-test     test             org.junit.vintage      junit-vintage-engine                        org.springframework.boot  spring-boot-dependencies  ${spring-boot.version}  pom  import                      org.apache.maven.plugins  maven-compiler-plugin  3.8.1        1.8      1.8      UTF-8              org.springframework.boot  spring-boot-maven-plugin  2.3.7.RELEASE        com.chen.Redis02SpringbootApplication             repackage   repackage                     

在使用RedisTemplate对Redis进行操作时,没有进行序列化操作会产生这样的问题:

 需要对数据进行序列化操作

首先我们可以找到依赖中RedisTemplate:

RedisTemplate的部分源码:

@Nullableprivate RedisSerializer keySerializer = null;@Nullableprivate RedisSerializer valueSerializer = null;@Nullableprivate RedisSerializer hashKeySerializer = null;if (this.defaultSerializer == null) {    this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());}if (this.enableDefaultSerializer) {    if (this.keySerializer == null) { this.keySerializer = this.defaultSerializer; defaultUsed = true;    }

如果给Redis传递对象,需要对对象进行序列化,如果不进行序列化,会存在乱码

即目标对象实现Serializable接口:

package com.chen.pojo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import org.springframework.stereotype.Component;import java.io.Serializable;/** * Created by 陈文杰 on 2022/5/26 13:38 */@Component@Data@AllArgsConstructor@NoArgsConstructorpublic class User implements Serializable {    private String name;    private int age;}

以上说明默认使用的是jdk的序列转化,而我们可能需要使用json来序列化

因此,我们需要自定义一个RedisTemplate类

在SpringBoot的RedisAutoConfiguration自动装配中有这样一个注解

@ConditionalOnMissingBean(name = "redisTemplate")

即只有在没有自定义RedisTemplated的情况下采用SpringBoot自动装配的RedisTemplated

因此我们可以根据需要自定义一个RedisTemplated类

自定义的RedisTemplated

package com.chen.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;import com.fasterxml.jackson.annotation.PropertyAccessor;import com.fasterxml.jackson.databind.ObjectMapper;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;@SuppressWarnings("all")@Configurationpublic class RedisConfig {    //编写我们自定义的RedisTemplated    @Bean    public RedisTemplate redisTemplate(RedisConnectionFactory factory) { //一般直接使用 RedisTemplate template = new RedisTemplate(); template.setConnectionFactory(factory); // 序列化配置(json ) Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); //String的序列化 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); template.setKeySerializer(stringRedisSerializer);// key采用String的序列化方式 template.setHashKeySerializer(stringRedisSerializer);// hash的key采用String的序列化方式 template.setValueSerializer(jackson2JsonRedisSerializer);// value采用jackson的序列化方式 template.setHashValueSerializer(jackson2JsonRedisSerializer);// hash的value采用jackson的序列化方式 template.afterPropertiesSet(); return template;    }}

测试:

package com.chen;import com.chen.pojo.User;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.ObjectMapper;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.connection.RedisConnection;import org.springframework.data.redis.core.RedisTemplate;@SpringBootTestclass Redis02SpringbootApplicationTests {    @Autowired    @Qualifier("redisTemplateDiy")    RedisTemplate redisTemplate;    @Test    void contextLoads() { System.out.println(redisTemplate.opsForValue().get("mykey"));// {//操作字符串//     redisTemplate.opsForValue();////     //操作list//     redisTemplate.opsForList();////     //操作set//     redisTemplate.opsForSet();////     //操作Zset//     redisTemplate.opsForZSet();////     //操作hash//     redisTemplate.opsForHash();////     //操作地点位置//     redisTemplate.opsForGeo();////     //操作基数//     redisTemplate.opsForHyperLogLog();// }// {//     //获取数据库连接(进行数据库层面的操作)//     RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();//     //清除所有数据//     connection.flushAll();////     //清除当前数据库数据//     connection.flushDb();// }    }    @Test    void test() throws JsonProcessingException { User user = new User("chen", 18); String jsonUser = new ObjectMapper().writeValueAsString(user); redisTemplate.opsForValue().set("user",jsonUser); System.out.println(redisTemplate.opsForValue().get("user"));    }}

问题解决

以上的测试代码比较繁琐,在真实的开发环境中并不会这样

我们可以写一个RedisUtils工具类,消去冗余代码:

有道云笔记

调用工具类测试:

@AutowiredRedisUtil redisUtil;@Testvoid test1(){    redisUtil.set("name","chen");    System.out.println(redisUtil.get("name"));}