SpringBoot中使用Redis-Lettuce
- 配置pom
- 在`application.properties`配置`Redis`参数
- 协议参数设置
- 序列化参数设置
- 实现工具`Redis`操作工具类
- 单条数据测试
- 批量测试
在
SpringBoot
中一般直接引用spring-boot-starter-data-redis
这个starter来使用Redis
,其中具体实现方式有两种方式
1、Lettuce
2、Jedis
配置pom
注意,这里我们使用
lettuce
,需要用到连接池信息,这里使用的是apache
的commons-pool2
<?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>3.3.3</version><relativePath/></parent><groupId>com.example</groupId><artifactId>demo</artifactId><version>0.0.1-SNAPSHOT</version><name>demo</name><properties><java.version>21</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>io.projectreactor</groupId><artifactId>reactor-core</artifactId><version>3.6.8</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.11.1</version></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></plugin></plugins></build>
</project>
在application.properties
配置Redis
参数
具体参数信息参考
org.springframework.boot.autoconfigure.data.redis.RedisProperties
,不同版本有些微差别
spring.application.name=demo
spring.data.redis.host=127.0.0.1
spring.data.redis.port=6379
spring.data.redis.password=XXXX
spring.data.redis.clientType=LETTUCE
spring.data.redis.lettuce.pool.enabled=true
spring.data.redis.lettuce.pool.min-idle=2
spring.data.redis.lettuce.pool.max-idle=20
spring.data.redis.lettuce.pool.max-active=20
spring.data.redis.lettuce.pool.max-wait=5000
协议参数设置
这里可以设置一些个性化的参数,其中一个就是协议版本,如果使用的
Redis
版本低于6.0,需要使用ProtocolVersion.RESP2
@Configuration
public class CustomLettuceClientConfigurationBuilderCustomizer implements LettuceClientConfigurationBuilderCustomizer {private static final int TIMEOUT = 30;private static final SocketOptions socketOptions = SocketOptions.builder().keepAlive(SocketOptions.KeepAliveOptions.builder().enable().idle(Duration.ofSeconds(TIMEOUT)).interval(Duration.ofSeconds(TIMEOUT / 3)).count(3).build()).tcpUserTimeout(SocketOptions.TcpUserTimeoutOptions.builder().enable().tcpUserTimeout(Duration.ofSeconds(TIMEOUT)).build()).build();@Overridepublic void customize(LettuceClientConfiguration.LettuceClientConfigurationBuilder clientConfigurationBuilder) {// redis 6.0以前版本需要使用ProtocolVersion.RESP2clientConfigurationBuilder.clientOptions(ClientOptions.builder().socketOptions(socketOptions).protocolVersion(ProtocolVersion.RESP3).build());}
}
序列化参数设置
1、这里直接使用的
StringRedisTemplate
,要求全部是字符串,序列化的工作交给调用方自己处理,
2、如果要扩展RedisTemplate<K, V>
,实现自己的特殊逻辑,这里就要设置key、value的序列化方式
@Configuration
public class RedisConfig {@Beanpublic StringRedisTemplate stringRedisTemplate(LettuceConnectionFactory factory) {// 验证是否可用factory.validateConnection();// 其他参数StringRedisTemplate template = new StringRedisTemplate();template.setConnectionFactory(factory);return template;}
}
实现工具Redis
操作工具类
public interface RedisService {/*** 写入缓存** @param key 缓存key* @param value 缓存value* @param timeout 超时时间* @param timeUnit 时间单位* @return*/void set(String key, String value, long timeout, TimeUnit timeUnit);/*** 获取缓存值** @param key 缓存key* @return*/String get(String key);
}@Service
public class RedisServiceImpl implements RedisService {@Autowiredprivate StringRedisTemplate redisTemplate;@Overridepublic void set(String key, String value, long timeout, TimeUnit timeUnit) {redisTemplate.opsForValue().set(key, value, timeout, timeUnit);}@Overridepublic String get(String key) {return redisTemplate.opsForValue().get(key);}
}
单条数据测试
@SpringBootTest
public class DemoApplicationTests {@Autowiredprivate RedisService redisService;@Testpublic void testSetGet() {String key = "hello";String value = "测试数据";redisService.set(key, value, 10, TimeUnit.SECONDS);Assertions.assertEquals(value, redisService.get(key));}
}
批量测试
这里主要测试一下连接池参数,找到一个合理配置
public class DemoApplicationTests {@Autowiredprivate RedisService redisService;@Testpublic void testPool() {this.testSetGet();ExecutorService executorService = Executors.newFixedThreadPool(10);int total = 10000;for (int i = 0; i < 10; i++) {int calcTotal = testPool(total, executorService);Assertions.assertEquals(calcTotal, total);}executorService.shutdown();executorService.close();}private int testPool(int total, ExecutorService executorService) {long start = System.currentTimeMillis();List<CompletableFuture<Integer>> list = IntStream.rangeClosed(1, total).mapToObj(it -> {return build(it, executorService);}).toList();CompletableFuture.allOf(list.toArray(CompletableFuture[]::new)).join();int calcTotal = list.stream().filter(Objects::nonNull).map(it -> {try {return it.get();} catch (Exception e) {return 0;}}).reduce(0, Integer::sum);long end = System.currentTimeMillis();System.out.println("耗时:" + (end - start) / 1000.0 + "s");return calcTotal;}private CompletableFuture<Integer> build(int it, ExecutorService executorService) {final String key = "test:hello:" + it;final String value = "value-" + it;return CompletableFuture.supplyAsync(() -> {try {redisService.set(key, value, 10, TimeUnit.SECONDS);boolean suc = value.equals(redisService.get(key));// System.out.println("build -> " + it + " -> " + Thread.currentThread().getName());if (!suc) {System.out.println("failed ->" + it);return 0;} else {return 1;}} catch (Exception e) {System.out.println("error ->" + it + ", " + e.getMessage());return 0;}}, executorService);}
}