Jedis vs Redisson vs Lettuce: Which Redis Java Client Fits Your Spring Boot Project?
This article compares the three popular Redis Java clients—Jedis, Redisson, and Lettuce—explaining their core differences, then shows how to configure and use Spring's RedisTemplate, RedissonClient, and annotation‑based caching with practical code examples and configuration files.
1. Differences between Jedis, Redisson, Lettuce
All three provide Java APIs for Redis, but they differ in blocking behavior, thread safety, and feature sets.
1.1 Jedis
Jedis is a synchronous client that uses blocking I/O; its instances are not thread‑safe and must be used via a connection pool.
1.2 Redisson
Redisson offers distributed locks, collections, delayed queues and other high‑level structures. It is built on Netty, uses asynchronous calls and provides a rich API.
1.3 Lettuce
Lettuce is thread‑safe, supports asynchronous and reactive usage, and works with clusters, Sentinel, pipelining and custom codecs.
2. RedisTemplate Usage
2.1 Maven Dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>2.2 Configuration (application‑dev.yml)
spring:
redis:
host: 192.168.1.140
port: 6379
password:
database: 152.3 Example Code
@Resource
private StringRedisTemplate stringRedisTemplate;
public CustomersEntity findById(Integer id) {
try {
String cached = stringRedisTemplate.opsForHash()
.get(REDIS_CUSTOMERS_ONE, id + "").toString();
if (cached != null) {
return JSONUtil.toBean(cached, CustomersEntity.class);
}
} catch (Exception e) {
e.printStackTrace();
}
Optional<CustomersEntity> byId = customerRepo.findById(id);
if (byId.isPresent()) {
CustomersEntity entity = byId.get();
try {
stringRedisTemplate.opsForHash()
.put(REDIS_CUSTOMERS_ONE, id + "", JSONUtil.toJsonStr(entity));
} catch (Exception e) {
e.printStackTrace();
}
return entity;
}
return null;
}2.4 StringRedisTemplate API (partial)
opsForHash – hash operations
opsForList – list operations
opsForSet – set operations
opsForValue – string operations
opsForZSet – sorted‑set operations
2.5 Default Serialization Mechanism
public class StringRedisTemplate extends RedisTemplate<String, String> {
public StringRedisTemplate() {
StringRedisSerializer stringSerializer = new StringRedisSerializer();
setKeySerializer(stringSerializer);
setValueSerializer(stringSerializer);
setHashKeySerializer(stringSerializer);
setHashValueSerializer(stringSerializer);
}
}3. RedissonClient Configuration and Usage
3.1 Maven Dependencies
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.8.2</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>LATEST</version>
</dependency>3.2 YAML Configuration (redisson-config.yml)
# Redisson configuration
singleServerConfig:
address: "redis://192.168.1.140:6379"
password: null
clientName: null
database: 15
idleConnectionTimeout: 10000
pingTimeout: 1000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
reconnectionTimeout: 3000
failedAttempts: 3
subscriptionsPerConnection: 5
subscriptionConnectionMinimumIdleSize: 1
subscriptionConnectionPoolSize: 50
connectionMinimumIdleSize: 32
connectionPoolSize: 64
dnsMonitoringInterval: 5000
threads: 0
nettyThreads: 0
codec: "org.redisson.codec.JsonJacksonCodec"
transportMode: "NIO"3.3 JSON Configuration (redisson-config.json)
{
"singleServerConfig": {
"address": "redis://192.168.1.140:6379",
"password": null,
"clientName": null,
"database": 0,
"idleConnectionTimeout": 10000,
"pingTimeout": 1000,
"connectTimeout": 10000,
"timeout": 3000,
"retryAttempts": 3,
"retryInterval": 1500,
"reconnectionTimeout": 3000,
"failedAttempts": 3,
"subscriptionsPerConnection": 5,
"subscriptionConnectionMinimumIdleSize": 1,
"subscriptionConnectionPoolSize": 50,
"connectionMinimumIdleSize": 10,
"connectionPoolSize": 64,
"dnsMonitoring": false,
"dnsMonitoringInterval": 5000
},
"threads": 0,
"nettyThreads": 0,
"codec": null,
"useLinuxNativeEpoll": false
}3.4 Java Configuration Class
@Configuration
public class RedissonConfig {
@Bean
public RedissonClient redisson() throws IOException {
Config config = Config.fromYAML(RedissonConfig.class
.getClassLoader()
.getResource("redisson-config.yml"));
return Redisson.create(config);
}
}3.5 Sample Controller Using RedissonClient
@RestController
@RequestMapping("/")
public class TeController {
@Autowired
private RedissonClient redissonClient;
static long i = 20;
static long sum = 300;
@GetMapping("/set/{key}")
public String s1(@PathVariable String key) {
RBucket<String> bucket = redissonClient.getBucket(key);
bucket.set(key + "1-v1");
return key;
}
@GetMapping("/get/{key}")
public String g1(@PathVariable String key) {
RBucket<String> bucket = redissonClient.getBucket(key);
return bucket.get();
}
@GetMapping("/hset/{key}")
public String h1(@PathVariable String key) {
Ur ur = new Ur();
ur.setId(MathUtil.randomLong(1, 20));
ur.setName(key);
RMap<String, Ur> map = redissonClient.getMap("UR");
map.put(ur.getId().toString(), ur);
return ur.toString();
}
@GetMapping("/hget/{id}")
public String h2(@PathVariable String id) {
RMap<String, Ur> map = redissonClient.getMap("UR");
Ur ur = map.get(id);
return ur.toString();
}
@GetMapping("/all")
public String all() {
RKeys keys = redissonClient.getKeys();
Iterable<String> allKeys = keys.getKeys();
allKeys.forEach(System.out::println);
return keys.toString();
}
@GetMapping("/rw/set/{key}")
public void rw_set() {
RBucket<String> bucket = redissonClient.getBucket("LS_COUNT");
bucket.set("300", 360000000L, TimeUnit.SECONDS);
}
@GetMapping("/jf")
public void jf() {
String key = "S_COUNT";
RAtomicLong atomic = redissonClient.getAtomicLong(key);
if (!atomic.isExists()) {
atomic.set(300L);
}
while (i == 0) {
if (atomic.get() > 0) {
long l = atomic.getAndDecrement();
try { Thread.sleep(1000L); } catch (InterruptedException e) { e.printStackTrace(); }
i--;
System.out.println(Thread.currentThread().getName() + "->" + i + "->" + l);
}
}
}
@GetMapping("/rw/get")
public String rw_get() {
String key = "S_COUNT";
Runnable r = () -> {
RAtomicLong atomic = redissonClient.getAtomicLong(key);
if (!atomic.isExists()) atomic.set(300L);
if (atomic.get() > 0) {
long l = atomic.getAndDecrement();
i--;
System.out.println(Thread.currentThread().getName() + "->" + i + "->" + l);
}
};
while (i != 0) {
new Thread(r).start();
}
RBucket<String> bucket = redissonClient.getBucket(key);
String s = bucket.get();
System.out.println("================线程已结束================================" + s);
return s;
}
}4. Annotation‑Based Redis Caching with Spring
4.1 Cache Configuration
@EnableCaching
@Configuration
@ConfigurationProperties(prefix = "spring.cache.redis")
public class RedisCacheConfig {
private Duration timeToLive = Duration.ZERO;
public void setTimeToLive(Duration ttl) { this.timeToLive = ttl; }
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> keySer = new StringRedisSerializer();
Jackson2JsonRedisSerializer<Object> valueSer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
valueSer.setObjectMapper(om);
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(timeToLive)
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSer))
.disableCachingNullValues();
return RedisCacheManager.builder(factory).cacheDefaults(config).build();
}
}4.2 Cacheable, CachePut and CacheEvict Examples
@Cacheable(value = "cache:customer", unless = "null == #result", key = "#id")
public CustomersEntity cacheOne(Integer id) {
return customerRepo.findById(id).orElse(null);
}
@Cacheable(value = "cache:customer", unless = "null == #result", key = "#root.methodName + '.' + #id")
public CustomersEntity cacheOne3(Integer id) {
return customerRepo.findById(id).orElse(null);
}
@CacheEvict(value = "cache:customer", key = "'cacheOne5.' + #id")
public void del(Integer id) { /* cache eviction */ }
@CacheEvict(value = "cache:customer", allEntries = true)
public void delAll() { /* clear all */ }
@Cacheable(value = "cache:all")
public List<CustomersEntity> cacheList() {
return customerRepo.findAll();
}
@CachePut(value = "cache:all", unless = "null == #result", key = "#root.methodName")
public List<CustomersEntity> cacheList2() {
return customerRepo.findAll();
}Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java High-Performance Architecture
Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
