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