连接到服务器
将您的 Java 应用程序连接到 Redis 数据库
基本连接
以下代码建立到本地 Redis 服务器的基本连接
package org.example;
import redis.clients.jedis.UnifiedJedis;
public class Main {
public static void main(String[] args) {
UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379");
// Code that interacts with Redis...
jedis.close();
}
}
连接后,您可以通过存储和检索简单的字符串值来检查连接
...
String res1 = jedis.set("bike:1", "Deimos");
System.out.println(res1); // OK
String res2 = jedis.get("bike:1");
System.out.println(res2); // Deimos
...
连接到 Redis 集群
要连接到 Redis 集群,请使用 JedisCluster
。
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.HostAndPort;
//...
Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7379));
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7380));
JedisCluster jedis = new JedisCluster(jedisClusterNodes);
使用 TLS 连接到您的生产环境 Redis
部署应用程序时,使用 TLS 并遵循 Redis 安全 指南。
将应用程序连接到启用 TLS 的 Redis 服务器之前,请确保您的证书和私钥格式正确。
要将用户证书和私钥从 PEM 格式转换为 pkcs12
,请使用此命令
openssl pkcs12 -export -in ./redis_user.crt -inkey ./redis_user_private.key -out redis-user-keystore.p12 -name "redis"
输入密码以保护您的 pkcs12
文件。
使用 JDK 附带的 keytool 将服务器 (CA) 证书转换为 JKS 格式。
keytool -importcert -keystore truststore.jks \
-storepass REPLACE_WITH_YOUR_PASSWORD \
-file redis_ca.pem
使用此代码片段与您的 Redis 数据库建立安全连接。
package org.example;
import redis.clients.jedis.*;
import javax.net.ssl.*;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
public class Main {
public static void main(String[] args) throws GeneralSecurityException, IOException {
HostAndPort address = new HostAndPort("my-redis-instance.cloud.redislabs.com", 6379);
SSLSocketFactory sslFactory = createSslSocketFactory(
"./truststore.jks",
"secret!", // use the password you specified for keytool command
"./redis-user-keystore.p12",
"secret!" // use the password you specified for openssl command
);
JedisClientConfig config = DefaultJedisClientConfig.builder()
.ssl(true).sslSocketFactory(sslFactory)
.user("default") // use your Redis user. More info https://redis.ac.cn/docs/latest/operate/oss_and_stack/management/security/acl/
.password("secret!") // use your Redis password
.build();
JedisPooled jedis = new JedisPooled(address, config);
jedis.set("foo", "bar");
System.out.println(jedis.get("foo")); // prints bar
}
private static SSLSocketFactory createSslSocketFactory(
String caCertPath, String caCertPassword, String userCertPath, String userCertPassword)
throws IOException, GeneralSecurityException {
KeyStore keyStore = KeyStore.getInstance("pkcs12");
keyStore.load(new FileInputStream(userCertPath), userCertPassword.toCharArray());
KeyStore trustStore = KeyStore.getInstance("jks");
trustStore.load(new FileInputStream(caCertPath), caCertPassword.toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
trustManagerFactory.init(trustStore);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX");
keyManagerFactory.init(keyStore, userCertPassword.toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
return sslContext.getSocketFactory();
}
}
使用客户端缓存连接
客户端缓存是一种减少客户端和服务器之间网络流量的技术,从而提高性能。有关客户端缓存如何工作以及如何有效使用它的更多信息,请参阅 客户端缓存简介。
要启用客户端缓存,请在连接期间指定 RESP3 协议并传递缓存配置对象。
以下示例显示了到默认主机和端口 localhost:6379
的最简单的客户端缓存连接。上面描述的所有连接变体都接受这些参数,因此您可以使用连接池或集群连接以完全相同的方式使用客户端缓存。
客户端缓存需要 Jedis v5.2.0 或更高版本。为了最大程度地兼容所有 Redis 产品,客户端缓存由 Redis v7.4 或更高版本支持。
Redis 服务器产品 支持 CSC 的 opt-in/opt-out 模式 和 broadcasting 模式,但 Jedis 目前尚未实现这些模式。
HostAndPort endpoint = new HostAndPort("localhost", 6379);
DefaultJedisClientConfig config = DefaultJedisClientConfig
.builder()
.password("secretPassword")
.protocol(RedisProtocol.RESP3)
.build();
CacheConfig cacheConfig = CacheConfig.builder().maxSize(1000).build();
UnifiedJedis client = new UnifiedJedis(endpoint, config, cacheConfig);
连接后,常用的 Redis 命令将透明地与缓存协同工作
client.set("city", "New York");
client.get("city"); // Retrieved from Redis server and cached
client.get("city"); // Retrieved from cache
如果您使用 redis-cli
连接到同一 Redis 数据库并运行 MONITOR
命令,您就可以看到缓存正在工作。如果您运行上面的代码但连接时不传递 cacheConfig
,您应该在 CLI 的 MONITOR
输出中看到以下内容
1723109720.268903 [...] "SET" "city" "New York"
1723109720.269681 [...] "GET" "city"
1723109720.270205 [...] "GET" "city"
服务器响应两次 get("city")
调用。如果再次添加 cacheConfig
运行代码,您将看到
1723110248.712663 [...] "SET" "city" "New York"
1723110248.713607 [...] "GET" "city"
第一个 get("city")
调用联系了服务器,但第二个调用由缓存满足。
从缓存中移除项目
您可以使用缓存对象的 deleteByRedisKey()
方法从缓存中移除单个键。这将移除与每个指定键关联的所有缓存项目,因此多键命令(例如 MGET
)和复合数据结构(例如 hashes)的所有结果将一次性清除。以下示例显示了从缓存中移除单个键的效果
client.hget("person:1", "name"); // Read from the server
client.hget("person:1", "name"); // Read from the cache
client.hget("person:2", "name"); // Read from the server
client.hget("person:2", "name"); // Read from the cache
Cache myCache = client.getCache();
myCache.deleteByRedisKey("person:1");
client.hget("person:1", "name"); // Read from the server
client.hget("person:1", "name"); // Read from the cache
client.hget("person:2", "name"); // Still read from the cache
您还可以使用 flush()
方法清除所有缓存项目
client.hget("person:1", "name"); // Read from the server
client.hget("person:1", "name"); // Read from the cache
client.hget("person:2", "name"); // Read from the server
client.hget("person:2", "name"); // Read from the cache
Cache myCache = client.getCache();
myCache.flush();
client.hget("person:1", "name"); // Read from the server
client.hget("person:1", "name"); // Read from the cache
client.hget("person:2", "name"); // Read from the server
client.hget("person:2", "name"); // Read from the cache
如果任何连接(包括来自连接池的连接)断开,客户端也将自动刷新缓存。
使用连接池连接
对于生产环境使用,您应该使用连接池来管理连接,而不是单独打开和关闭连接。连接池维护多个打开的连接并有效地重用它们。当您从连接池打开一个连接时,连接池会分配其一个打开的连接。当您随后关闭同一个连接时,它实际上并未关闭,而是简单地返回到连接池以供重用。这避免了重复连接和断开连接的开销。有关更多信息,请参阅 连接池和多路复用。
使用以下代码连接连接池
package org.example;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class Main {
public static void main(String[] args) {
JedisPool pool = new JedisPool("localhost", 6379);
try (Jedis jedis = pool.getResource()) {
// Store & Retrieve a simple string
jedis.set("foo", "bar");
System.out.println(jedis.get("foo")); // prints bar
// Store & Retrieve a HashMap
Map<String, String> hash = new HashMap<>();;
hash.put("name", "John");
hash.put("surname", "Smith");
hash.put("company", "Redis");
hash.put("age", "29");
jedis.hset("user-session:123", hash);
System.out.println(jedis.hgetAll("user-session:123"));
// Prints: {name=John, surname=Smith, company=Redis, age=29}
}
}
}
由于为每个命令添加 try-with-resources
块可能很麻烦,请考虑使用 JedisPooled
作为更简单的连接池方式。JedisPooled
在 Jedis 版本 4.0.0 中添加,提供与 JedisPool
类似的功能,但 API 更简单直观。
import redis.clients.jedis.JedisPooled;
//...
JedisPooled jedis = new JedisPooled("localhost", 6379);
jedis.set("foo", "bar");
System.out.println(jedis.get("foo")); // prints "bar"
连接池持有指定数量的连接,在必要时创建更多连接,并在不再需要时终止它们。
以下是连接池中简化的连接生命周期
- 从连接池请求连接。
- 连接被提供
- 当非活动连接可用时,提供一个空闲连接,或者
- 当连接数低于
maxTotal
时,创建新连接。
- 连接变为活动状态。
- 连接被释放回连接池。
- 连接被标记为陈旧。
- 连接保持空闲状态达
minEvictableIdleTime
。 - 如果连接数大于
minIdle
,则连接变为可驱逐状态。 - 连接已准备好关闭。
正确配置连接池非常重要。使用 Apache Commons Pool2 中的 GenericObjectPoolConfig
。
ConnectionPoolConfig poolConfig = new ConnectionPoolConfig();
// maximum active connections in the pool,
// tune this according to your needs and application type
// default is 8
poolConfig.setMaxTotal(8);
// maximum idle connections in the pool, default is 8
poolConfig.setMaxIdle(8);
// minimum idle connections in the pool, default 0
poolConfig.setMinIdle(0);
// Enables waiting for a connection to become available.
poolConfig.setBlockWhenExhausted(true);
// The maximum number of seconds to wait for a connection to become available
poolConfig.setMaxWait(Duration.ofSeconds(1));
// Enables sending a PING command periodically while the connection is idle.
poolConfig.setTestWhileIdle(true);
// controls the period between checks for idle connections in the pool
poolConfig.setTimeBetweenEvictionRuns(Duration.ofSeconds(1));
// JedisPooled does all hard work on fetching and releasing connection to the pool
// to prevent connection starvation
JedisPooled jedis = new JedisPooled(poolConfig, "localhost", 6379);