【Redis】 SpringBoot集成Redis
SpringBoot 操作数据:spring-data、jpa、jdbc、mongodb、redis!
SpringData 也是和 SpringBoot 齐名的项目!
Spring Data Redis(Lettuce)
现在的Redis操作底层已经不再使用Jedis,SpringBoot 2.*之后换成了Lettuce;
- Jedis使用的是直连模式,在多个线程中操作的话,是不安全的,如果想要避免不安全,使用jedis pool连接池,BIO模式;
- Lettuce使用的Netty,可以在多个线程中进行共享,不存在线程连接不安全的情况,可以减少线程数据,更像NIO模式;
新版的RedisAutoConfiguration:


SpringBoot 2.x的内容
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
// 我们可以自己定义一个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;
}
@Bean
@ConditionalOnMissingBean // 由于 String 是redis中最常使用的类型,所以说单独提出来了一个bean!
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {StringRedisTemplate template = new StringRedisTemplate();template.setConnectionFactory(redisConnectionFactory);return template;
}
SpringBoot的配置类都有一个自动配置类@AutoConfigeration,每个自动配置类会自动绑定一个properties文件,依次找到自己的配置类的完全限界名。
项目实战
- 导入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 配置application.xml
之前是spring.redis中,后来迁移到springdata项目中
spring:data:redis:host: localhostport: 6379password: "" # 如果有密码database: 0timeout: 2000ms
- 进行测试
- 发现问题

测试时发现问题,结合博客进行学习Springboot整合Redis时遇到的一些问题_无法自动装配。找不到 ‘redistemplate<string, object>’ 类型的 bea-CSDN博客
- 尝试自定义Configuration进行解决问题
- 忘记加启动类了,注意加上启动类,注意要有
@SpringBootApplication注解
自定义RedisTemplate
- 新建一个Config,编写配置类
- 将AutoConfiguration的内容copy过去,更改
@ConditionalOnMissingBean(name = {"redisTemplate"}),有redisTemplate的场景,就不会加载默认的redisTemplate模板;
package com.cloud.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisConfig {@BeanLettuceConnectionFactory connectionFactory() {return new LettuceConnectionFactory();}@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(redisConnectionFactory);template.setKeySerializer(new StringRedisSerializer());template.setHashKeySerializer(new StringRedisSerializer());GenericJackson2JsonRedisSerializer jsonSerializer =new GenericJackson2JsonRedisSerializer();template.setValueSerializer(jsonSerializer);template.setHashValueSerializer(jsonSerializer);template.afterPropertiesSet();return template;}
}
- 编写方法类
package com.cloud.redisTs;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;@Component
public class RedisServiceCustom {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;void contextLoadService() {// 通过redisTemplate操作redis// String类型操作redisTemplate.opsForValue().set("name", "张三");System.out.println("String value:\t"+redisTemplate.opsForValue().get("name"));// 数字递增redisTemplate.opsForValue().set("counter", 1);redisTemplate.opsForValue().increment("counter", 1);System.out.println("Increment counter:\t"+redisTemplate.opsForValue().get("counter"));redisTemplate.opsForList().leftPush("list", "张三");redisTemplate.opsForList().leftPush("list", "李四");redisTemplate.opsForList().leftPush("list", "王五");System.out.println("List size:\t"+ redisTemplate.opsForList().size("list"));System.out.println("List all:\t"+ redisTemplate.opsForList().range("list", 0, -1));// 获取List元素System.out.println("List first:\t"+redisTemplate.opsForList().index("list", 0));System.out.println("List last:\t"+redisTemplate.opsForList().index("list", -1));System.out.println("Left pop:\t"+redisTemplate.opsForList().leftPop("list"));System.out.println("Right pop:\t"+redisTemplate.opsForList().rightPop("list"));// Set类型操作redisTemplate.opsForSet().add("set", "apple");redisTemplate.opsForSet().add("set", "banana");redisTemplate.opsForSet().add("set", "orange");redisTemplate.opsForSet().add("set", "apple"); // 重复元素不会添加System.out.println("Set members:\t"+redisTemplate.opsForSet().members("set"));System.out.println("Set size:\t"+redisTemplate.opsForSet().size("set"));System.out.println("Is member apple:\t"+redisTemplate.opsForSet().isMember("set", "apple"));// ZSet(有序集合)操作redisTemplate.opsForZSet().add("zset", "one", 1);redisTemplate.opsForZSet().add("zset", "two", 2);redisTemplate.opsForZSet().add("zset", "three", 3);System.out.println("ZSet members:\t"+redisTemplate.opsForZSet().range("zset", 0, -1));System.out.println("ZSet reverse:\t"+redisTemplate.opsForZSet().reverseRange("zset", 0, -1));System.out.println("ZSet score of 'two':\t"+redisTemplate.opsForZSet().score("zset", "two"));// Hash类型操作redisTemplate.opsForHash().put("user:1000", "name", "张三");redisTemplate.opsForHash().put("user:1000", "age", "25");redisTemplate.opsForHash().put("user:1000", "email", "zhangsan@example.com");System.out.println("Hash all:\t"+redisTemplate.opsForHash().entries("user:1000"));System.out.println("Hash name:\t"+redisTemplate.opsForHash().get("user:1000", "name"));System.out.println("Hash keys:\t"+redisTemplate.opsForHash().keys("user:1000"));// Geo地理位置操作redisTemplate.opsForGeo().add("cities", new org.springframework.data.geo.Point(116.405285, 39.904989), "北京");redisTemplate.opsForGeo().add("cities", new org.springframework.data.geo.Point(121.472644, 31.231706), "上海");redisTemplate.opsForGeo().add("cities", new org.springframework.data.geo.Point(113.280661, 23.125178), "广州");// 获取位置信息System.out.println("Geo position of 北京:\t"+redisTemplate.opsForGeo().position("cities", "北京"));// 计算距离 (默认米)System.out.println("Distance between 北京 and 上海:\t"+redisTemplate.opsForGeo().distance("cities", "北京", "上海"));}}
- 测试
package com.cloud.redisTs;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;@SpringBootTest
public class RedisTest {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Autowiredprivate RedisServiceCustom redisService;@Testpublic void contextLoads() {redisService.contextLoadService();}@Testpublic void testRedis() {redisTemplate.opsForValue().set("name", "张三");System.out.println(redisTemplate.opsForValue().get("name"));}
}
- 测试完成
String value: 张三
Increment counter: 2
List size: 16
List all: [王五, 李四, 张三, 李四, 张三, 李四, 张三, 王五, 李四, 张三, 王五, 李四, 张三, 王五, 李四, 张三]
List first: 王五
List last: 张三
Left pop: 王五
Right pop: 张三
Set members: [apple, banana, orange]
Set size: 3
Is member apple: true
ZSet members: [one, two, three]
ZSet reverse: [three, two, one]
ZSet score of 'two': 2.0
Hash all: {name=张三, age=25, email=zhangsan@example.com}
Hash name: 张三
Hash keys: [name, age, email]
Geo position of 北京: [Point [x=116.405283, y=39.904988]]
Distance between 北京 and 上海: 1067597.9668 METERS