Connect to the server
Connect your Java application to a Redis database
Start by creating a connection to your Redis server. There are many ways to achieve this using Lettuce. Here are a few.
Basic connection
import io.lettuce.core.*;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
public class ConnectBasicTest {
public void connectBasic() {
RedisURI uri = RedisURI.Builder
.redis("localhost", 6379)
.withAuthentication("default", "yourPassword")
.build();
RedisClient client = RedisClient.create(uri);
StatefulRedisConnection<String, String> connection = client.connect();
RedisCommands<String, String> commands = connection.sync();
commands.set("foo", "bar");
String result = commands.get("foo");
System.out.println(result); // >>> bar
connection.close();
client.shutdown();
}
}
Connect to a Redis cluster
To connect to a Redis cluster, use RedisClusterClient.
import io.lettuce.core.cluster.RedisClusterClient;
import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;
//...
try (RedisClusterClient clusterClient = RedisClusterClient.create(redisURI)) {
StatefulRedisClusterConnection<String, String> connection = clusterClient.connect();
//...
connection.close();
}
Learn more about Cluster connections and how to configure them in the reference guide.
Asynchronous connection
package org.example;
import java.util.*;
import java.util.concurrent.ExecutionException;
import io.lettuce.core.*;
import io.lettuce.core.api.async.RedisAsyncCommands;
import io.lettuce.core.api.StatefulRedisConnection;
public class Async {
public static void main(String[] args) {
RedisClient redisClient = RedisClient.create("redis://localhost:6379");
try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {
RedisAsyncCommands<String, String> asyncCommands = connection.async();
// Asynchronously store & retrieve a simple string
asyncCommands.set("foo", "bar").get();
System.out.println(asyncCommands.get("foo").get()); // prints bar
// Asynchronously store key-value pairs in a hash directly
Map<String, String> hash = new HashMap<>();
hash.put("name", "John");
hash.put("surname", "Smith");
hash.put("company", "Redis");
hash.put("age", "29");
asyncCommands.hset("user-session:123", hash).get();
System.out.println(asyncCommands.hgetall("user-session:123").get());
// Prints: {name=John, surname=Smith, company=Redis, age=29}
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
} finally {
redisClient.shutdown();
}
}
}
Learn more about asynchronous Lettuce API in the reference guide.
Reactive connection
package org.example;
import java.util.*;
import io.lettuce.core.*;
import io.lettuce.core.api.reactive.RedisReactiveCommands;
import io.lettuce.core.api.StatefulRedisConnection;
public class Main {
public static void main(String[] args) {
RedisClient redisClient = RedisClient.create("redis://localhost:6379");
try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {
RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();
// Reactively store & retrieve a simple string
reactiveCommands.set("foo", "bar").block();
reactiveCommands.get("foo").doOnNext(System.out::println).block(); // prints bar
// Reactively store key-value pairs in a hash directly
Map<String, String> hash = new HashMap<>();
hash.put("name", "John");
hash.put("surname", "Smith");
hash.put("company", "Redis");
hash.put("age", "29");
reactiveCommands.hset("user-session:124", hash).then(
reactiveCommands.hgetall("user-session:124")
.collectMap(KeyValue::getKey, KeyValue::getValue).doOnNext(System.out::println))
.block();
// Prints: {surname=Smith, name=John, company=Redis, age=29}
} finally {
redisClient.shutdown();
}
}
}
Learn more about reactive Lettuce API in the reference guide.
Connect to a Redis cluster
import io.lettuce.core.RedisURI;
import io.lettuce.core.cluster.RedisClusterClient;
import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;
import io.lettuce.core.cluster.api.async.RedisAdvancedClusterAsyncCommands;
// ...
RedisURI redisUri = RedisURI.Builder.redis("localhost").withPassword("authentication").build();
RedisClusterClient clusterClient = RedisClusterClient.create(redisUri);
StatefulRedisClusterConnection<String, String> connection = clusterClient.connect();
RedisAdvancedClusterAsyncCommands<String, String> commands = connection.async();
// ...
connection.close();
clusterClient.shutdown();
TLS connection
When you deploy your application, use TLS and follow the Redis security guidelines.
RedisURI redisUri = RedisURI.Builder.redis("localhost")
.withSsl(true)
.withPassword("secret!") // use your Redis password
.build();
RedisClient client = RedisClient.create(redisUri);
Connection Management in Lettuce
Lettuce uses ClientResources for efficient management of shared resources like event loop groups and thread pools.
For connection pooling, Lettuce leverages RedisClient or RedisClusterClient, which can handle multiple concurrent connections efficiently.
Connection pooling
A typical approach with Lettuce is to create a single RedisClient instance and reuse it to establish connections to your Redis server(s).
These connections are multiplexed; that is, multiple commands can be run concurrently over a single or a small set of connections, making explicit pooling less practical.
See
Connection pools and multiplexing
for more information.
Lettuce provides pool config to be used with Lettuce asynchronous connection methods.
package org.example;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.TransactionResult;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.async.RedisAsyncCommands;
import io.lettuce.core.codec.StringCodec;
import io.lettuce.core.support.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
public class Pool {
public static void main(String[] args) {
RedisClient client = RedisClient.create();
String host = "localhost";
int port = 6379;
CompletionStage<BoundedAsyncPool<StatefulRedisConnection<String, String>>> poolFuture
= AsyncConnectionPoolSupport.createBoundedObjectPoolAsync(
() -> client.connectAsync(StringCodec.UTF8, RedisURI.create(host, port)),
BoundedPoolConfig.create());
// await poolFuture initialization to avoid NoSuchElementException: Pool exhausted when starting your application
AsyncPool<StatefulRedisConnection<String, String>> pool = poolFuture.toCompletableFuture()
.join();
// execute work
CompletableFuture<TransactionResult> transactionResult = pool.acquire()
.thenCompose(connection -> {
RedisAsyncCommands<String, String> async = connection.async();
async.multi();
async.set("key", "value");
async.set("key2", "value2");
System.out.println("Executed commands in pipeline");
return async.exec().whenComplete((s, throwable) -> pool.release(connection));
});
transactionResult.join();
// terminating
pool.closeAsync();
// after pool completion
client.shutdownAsync();
}
}
In this setup, LettuceConnectionFactory is a custom class you would need to implement, adhering to Apache Commons Pool's PooledObjectFactory interface, to manage lifecycle events of pooled StatefulRedisConnection objects.
Connect using Smart client handoffs (SCH)
Smart client handoffs (SCH) is a feature of Redis Cloud and Redis Enterprise servers that lets them actively notify clients about planned server maintenance shortly before it happens. This lets a client take action to avoid disruptions in service. See Smart client handoffs for more information about SCH.
To enable SCH on the client, create a MaintNotificationsConfig object
and/or a TimeoutOptions object
and pass them to the ClientOptions builder as shown in the example below:
import io.lettuce.core.*;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.protocol.ProtocolVersion;
import java.time.Duration;
// ...
// ...
RedisClient redisClient = RedisClient.create("redis://localhost:6379");
MaintNotificationsConfig maintNotificationsConfig = MaintNotificationsConfig.builder()
.enableMaintNotifications()
// .autoResolveEndpointType() // default is auto-resolve
.endpointType(EndpointType.INTERNAL_IP)
.build();
TimeoutOptions timeoutOptions = TimeoutOptions.builder()
.relaxedTimeoutsDuringMaintenance(Duration.ofSeconds(10))
.build();
ClientOptions clientOptions = ClientOptions.builder()
.maintNotificationsConfig(maintNotificationsConfig)
.timeoutOptions(timeoutOptions)
.build();
redisClient.setOptions(clientOptions);
// or
ClientOptions clientOptions = ClientOptions.builder()
.maintNotificationsConfig(MaintNotificationsConfig.enabled(EndpointType.INTERNAL_IP))
.build();
redisClient.setOptions(clientOptions);
// or
ClientOptions clientOptions = ClientOptions.builder()
.maintNotificationsConfig(MaintNotificationsConfig.enabled())
.build();
redisClient.setOptions(clientOptions);
The MaintNotificationsConfig builder accepts the following options:
| Method | Description |
|---|---|
enableMaintNotifications() |
Enable SCH. |
endpointType(EndpointType type) |
Set the type of endpoint to use for the connection. The options are EndpointType.EXTERNAL_IP, EndpointType.INTERNAL_IP, EndpointType.EXTERNAL_FQDN, EndpointType.INTERNAL_FQDN, and EndpointType.NONE. Use the separate autoResolveEndpointType() method to auto-detect based on the connection (this is the default behavior). |
autoResolveEndpointType() |
Auto-detect the type of endpoint to use for the connection. This is the default behavior. Use endpointType() to set a specific endpoint type. |
Among other options, the TimeoutOptions builder accepts the following option
that is relevant to SCH:
| Method | Description |
|---|---|
relaxedTimeoutsDuringMaintenance(Duration duration) |
Set the timeout to use while the server is performing maintenance. The default is 10 seconds. |