SpringBoot中使用Redis-Jedis
在
SpringBoot
中一般直接引用spring-boot-starter-data-redis
这个starter来使用Redis
,其中具体实现方式有两种方式
1、Lettuce
2、Jedis
配置pom
注意,这里默认使用
lettuce
,如果需要使用jedis
,需要把lettuce
排除掉
<?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/> <!-- lookup parent from repository -->
</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>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>5.1.5</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.clientType=JEDIS
spring.data.redis.jedis.pool.enabled=true
spring.data.redis.jedis.pool.min-idle=1
spring.data.redis.jedis.pool.max-idle=10
spring.data.redis.jedis.pool.max-active=10
spring.data.redis.jedis.pool.max-wait=5000
序列化参数设置
1、这里直接使用的
StringRedisTemplate
,要求全部是字符串,序列化的工作交给调用方自己处理,
2、如果要扩展RedisTemplate<K, V>
,实现自己的特殊逻辑,这里就要设置key、value的序列化方式
@Configuration
public class RedisConfig {
@Bean
public StringRedisTemplate stringRedisTemplate(JedisConnectionFactory factory) {
// 其他参数
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 {
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public void set(String key, String value, long timeout, TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}
@Override
public String get(String key) {
return redisTemplate.opsForValue().get(key);
}
}
单条测试
@SpringBootTest
public class DemoApplicationTests {
@Autowired
private RedisService redisService;
@Test
public void testSetGet() {
String key = "hello";
String value = "测试数据";
redisService.set(key, value, 10, TimeUnit.SECONDS);
Assertions.assertEquals(value, redisService.get(key));
}
}
批量测试
public class DemoApplicationTests {
@Autowired
private RedisService redisService;
@Test
public 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);
}
}