杰瑞科技汇

Redis Java客户端如何高效连接与使用?

Of course! Here is a comprehensive guide to using Redis with a Java client, covering the most popular client, Lettuce, with detailed examples, best practices, and comparisons.

Redis Java客户端如何高效连接与使用?-图1
(图片来源网络,侵删)

Choosing a Java Client

There are two main, modern Java clients for Redis:

  1. Lettuce: The recommended and most popular choice for new projects. It is a fully non-blocking, asynchronous, and reactive client built on Netty. It supports synchronous, asynchronous, and reactive programming models.
  2. Jedis: The original and most well-known Java client. It is a blocking, synchronous client. While still widely used and functional, it's considered legacy for new development compared to Lettuce.

Recommendation: Use Lettuce for any new application. Its non-blocking nature provides better performance and scalability, especially in modern, high-concurrency environments like Spring Boot.


Getting Started with Lettuce

This section will walk you through setting up a simple Java project using Lettuce.

Step 1: Add Dependencies

You'll need the Lettuce core dependency and a connection pool. The connection pool is crucial for performance in most applications.

Redis Java客户端如何高效连接与使用?-图2
(图片来源网络,侵删)

If you're using Maven, add this to your pom.xml:

<dependency>
    <groupId>io.lettuce</groupId>
    <artifactId>lettuce-core</artifactId>
    <version>6.3.2.RELEASE</version> <!-- Use the latest version -->
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.12.0</version> <!-- Use the latest version -->
</dependency>

If you're using Gradle, add this to your build.gradle:

implementation 'io.lettuce:lettuce-core:6.3.2.RELEASE' // Use the latest version
implementation 'org.apache.commons:commons-pool2:2.12.0' // Use the latest version

Step 2: Basic Synchronous Example

This is the simplest way to interact with Redis. Lettuce handles the connection for you automatically.

import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
public class LettuceSyncExample {
    public static void main(String[] args) {
        // 1. Create a Redis URI
        // For a local Redis instance, RedisURI.create("redis://localhost")
        RedisURI redisURI = RedisURI.create("redis://localhost:6379");
        // 2. Create a Redis client
        RedisClient redisClient = RedisClient.create(redisURI);
        try {
            // 3. Create a connection (this is a blocking, synchronous connection)
            StatefulRedisConnection<String, String> connection = redisClient.connect();
            // 4. Get a synchronous interface for commands
            RedisCommands<String, String> syncCommands = connection.sync();
            // 5. Execute commands
            System.out.println("Setting a key: 'name' to 'Alice'");
            syncCommands.set("name", "Alice");
            System.out.println("Getting the value for key 'name': " + syncCommands.get("name"));
            System.out.println("Setting a hash field: 'user:1001:email' to 'alice@example.com'");
            syncCommands.hset("user:1001", "email", "alice@example.com");
            syncCommands.hset("user:1001", "name", "Alice Smith");
            System.out.println("Getting all fields for hash 'user:1001': " + syncCommands.hgetall("user:1001"));
            // 6. Close the connection
            connection.close();
        } finally {
            // 7. Shutdown the client
            redisClient.shutdown();
        }
    }
}

Step 3: Using a Connection Pool (Recommended)

Creating a new connection for every operation is inefficient. A connection pool reuses connections, significantly improving performance.

Redis Java客户端如何高效连接与使用?-图3
(图片来源网络,侵删)
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.support.ConnectionPool;
import io.lettuce.core.support.ConnectionPoolSupport;
import java.util.concurrent.TimeUnit;
public class LettucePoolExample {
    public static void main(String[] args) {
        // 1. Create a Redis URI
        RedisURI redisURI = RedisURI.create("redis://localhost:6379");
        // 2. Create a Redis client
        RedisClient redisClient = RedisClient.create(redisURI);
        // 3. Create a connection pool
        // The pool will manage up to 20 connections
        ConnectionPool<StatefulRedisConnection<String, String>> pool = ConnectionPoolSupport.createGenericObjectPool(
                () -> redisClient.connect(),
                20 // max total connections
        );
        try {
            // 4. Borrow a connection from the pool
            StatefulRedisConnection<String, String> connection = pool.borrowObject();
            try {
                // 5. Use the connection
                RedisCommands<String, String> syncCommands = connection.sync();
                syncCommands.set("pool_key", "Hello from a pooled connection!");
                System.out.println("Value from pool: " + syncCommands.get("pool_key"));
            } finally {
                // 6. Return the connection to the pool
                pool.returnObject(connection);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 7. Shutdown the pool and the client
            pool.close();
            redisClient.shutdown();
        }
    }
}

Advanced Features of Lettuce

Asynchronous Programming

Lettuce is built on Netty, making asynchronous operations first-class citizens. This is great for high-throughput applications.

import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.async.RedisAsyncCommands;
import io.lettuce.core.api.StatefulRedisConnection;
import java.util.concurrent.CompletableFuture;
public class LettuceAsyncExample {
    public static void main(String[] args) {
        RedisURI redisURI = RedisURI.create("redis://localhost:6379");
        RedisClient redisClient = RedisClient.create(redisURI);
        try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {
            // Get an asynchronous commands interface
            RedisAsyncCommands<String, String> asyncCommands = connection.async();
            // Commands now return CompletableFuture
            CompletableFuture<String> futureSet = asyncCommands.set("async_key", "async_value");
            CompletableFuture<String> futureGet = asyncCommands.get("async_key");
            // You can chain operations or use callbacks
            futureGet.thenAccept(value -> {
                System.out.println("Async Get Result: " + value);
            }).exceptionally(ex -> {
                System.err.println("An error occurred: " + ex.getMessage());
                return null;
            });
            // Wait for the asynchronous operations to complete
            // In a real application, you'd use a more sophisticated event loop
            futureSet.join(); // Blocks until this future is done
            futureGet.join(); // Blocks until this future is done
            System.out.println("Async operations completed.");
        } finally {
            redisClient.shutdown();
        }
    }
}

Reactive Programming (Project Reactor)

For modern, reactive stack applications (like Spring WebFlux), Lettuce provides a reactive API that integrates seamlessly with Project Reactor.

import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.reactive.RedisReactiveCommands;
import reactor.core.publisher.Mono;
public class LettuceReactiveExample {
    public static void main(String[] args) {
        RedisURI redisURI = RedisURI.create("redis://localhost:6379");
        RedisClient redisClient = RedisClient.create(redisURI);
        try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {
            // Get a reactive commands interface
            RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();
            // Commands return Mono or Flux
            Mono<String> setMono = reactiveCommands.set("reactive_key", "reactive_value");
            Mono<String> getMono = reactiveCommands.get("reactive_key");
            // Chain operations using reactive operators
            getMono
                .doOnSuccess(value -> System.out.println("Reactive Get Result: " + value))
                .doOnError(error -> System.err.println("Error: " + error.getMessage()))
                .block(); // Block to see the result in this simple example
            System.out.println("Reactive operation completed.");
        } finally {
            redisClient.shutdown();
        }
    }
}

Spring Boot Integration

Spring Boot makes using Redis incredibly easy with autoconfiguration. It defaults to using Lettuce with a connection pool.

Step 1: Add the Spring Boot Starter Data Redis

<!-- Maven -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

Step 2: Configure Redis in application.properties

# application.properties or application.yml
spring.redis.host=localhost
spring.redis.port=6379
# For production, use a strong password
# spring.redis.password=yourpassword

That's it! Spring Boot automatically configures a RedisTemplate and a StringRedisTemplate for you.

Step 3: Use @Autowired to Inject and Use RedisTemplate

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.Map;
@SpringBootApplication
public class RedisApplication implements CommandLineRunner {
    // For String keys and values
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    // For generic objects (requires serialization)
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    public static void main(String[] args) {
        SpringApplication.run(RedisApplication.class, args);
    }
    @Override
    public void run(String... args) throws Exception {
        // --- Using StringRedisTemplate ---
        System.out.println("--- Using StringRedisTemplate ---");
        stringRedisTemplate.opsForValue().set("spring:name", "Bob");
        String name = stringRedisTemplate.opsForValue().get("spring:name");
        System.out.println("Name from Redis: " + name);
        // --- Using RedisTemplate for Objects ---
        System.out.println("\n--- Using RedisTemplate for Objects ---");
        User user = new User(2L, "Charlie", "charlie@example.com");
        redisTemplate.opsForValue().set("user:2", user);
        User retrievedUser = (User) redisTemplate.opsForValue().get("user:2");
        System.out.println("Retrieved User: " + retrievedUser);
        // --- Using Hash Operations ---
        System.out.println("\n--- Using Hash Operations ---");
        stringRedisTemplate.opsForHash().put("user:3:details", "name", "David");
        stringRedisTemplate.opsForHash().put("user:3:details", "email", "david@example.com");
        Map<Object, Object> userDetails = stringRedisTemplate.opsForHash().entries("user:3:details");
        System.out.println("User Details Hash: " + userDetails);
    }
    // A simple POJO to be stored in Redis
    static class User {
        private Long id;
        private String name;
        private String email;
        // Constructors, Getters, and Setters are required for serialization
        public User() {}
        public User(Long id, String name, String email) {
            this.id = id;
            this.name = name;
            this.email = email;
        }
        @Override
        public String toString() {
            return "User{id=" + id + ", name='" + name + "', email='" + email + "'}";
        }
        // Getters and Setters...
        public Long getId() { return id; }
        public void setId(Long id) { this.id = id; }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getEmail() { return email; }
        public void setEmail(String email) { this.email = email; }
    }
}

Jedis (Legacy) Quick Comparison

If you encounter a project using Jedis, here's how it compares.

Key Differences

Feature Lettuce Jedis
Model Non-blocking, Asynchronous/Reactive Blocking, Synchronous
I/O Netty Java Socket
Connection Handling Can manage its own connections or use a pool. Requires a pool. Requires a connection pool (JedisPool) for performance.
Threading One connection per thread is not needed. A single thread can handle many connections. Each connection is thread-unsafe. You must get a connection from the pool for each operation.
Recommendation Recommended for new projects. Legacy, but still functional.

Jedis Code Example (for comparison)

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisExample {
    public static void main(String[] args) {
        // 1. Configure and create a connection pool (mandatory for performance)
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(20);
        JedisPool jedisPool = new JedisPool(poolConfig, "localhost", 6379);
        // 2. Borrow a resource from the pool
        try (Jedis jedis = jedisPool.getResource()) {
            // 3. Use the resource
            jedis.set("jedis_key", "Hello from Jedis!");
            String value = jedis.get("jedis_key");
            System.out.println("Value from Jedis: " + value);
        } finally {
            // 4. Close the pool when the application shuts down
            jedisPool.close();
        }
    }
}

Summary

  • For new Java projects, always choose Lettuce.
  • Lettuce supports synchronous, asynchronous, and reactive programming models.
  • Always use a connection pool (Lettuce's GenericObjectPool or Spring Boot's auto-configured one) for production applications to manage connections efficiently.
  • Spring Boot makes integration trivial with spring-boot-starter-data-redis, which defaults to Lettuce.
  • Jedis is the legacy, synchronous client. It works but is not suitable for modern, high-performance, non-blocking architectures.
分享:
扫描分享到社交APP
上一篇
下一篇