Jedis
GitHub概要
redis/jedis
Redis Java client
スター12,173
ウォッチ675
フォーク3,902
作成日:2010年6月11日
言語:Java
ライセンス:MIT License
トピックス
javajedisredisredis-clientredis-cluster
スター履歴
データ取得日時: 2025/10/22 09:55
キャッシュライブラリ
Jedis
概要
JedisはJava用の公式Redisクライアントライブラリで、高性能な接続プーリング、Redis Cluster、Sentinel、RediSearch、RedisJSONなどのRedis全機能をサポートします。
詳細
JedisはRedis Labsが開発・メンテナンスしているJava向けの公式Redisクライアントライブラリです。シンプルで直感的なAPIを提供しながら、Redisの全機能にアクセスできます。JedisPoolを使った効率的な接続管理、Redis Clusterでの分散処理、Redis Sentinelによる高可用性、パイプライニングとトランザクション、Pub/Subメッセージング、Lua scriptingサポートなど、エンタープライズレベルの機能を網羅しています。JedisPooledクラスにより、従来のtry-with-resourcesパターンを簡略化し、より簡潔なコードでRedis操作が可能です。RediSearch、RedisJSON、RedisTimeSeries等のRedisモジュールにも対応し、高度な検索やJSON操作、時系列データ処理も実現できます。Maven、Gradleでの簡単な導入、豊富なドキュメント、アクティブなコミュニティサポートにより、Javaエコシステムでの標準的なRedisクライアントとして広く採用されています。
メリット・デメリット
メリット
- 公式サポート: Redis Labsによる公式開発・メンテナンス
- 豊富な機能: Redis全機能とモジュール(RediSearch、RedisJSON等)サポート
- 高性能接続プーリング: JedisPoolによる効率的なリソース管理
- 簡潔なAPI: 直感的で使いやすいJava APIデザイン
- クラスタサポート: Redis Clusterの自動検出とフェイルオーバー
- エンタープライズ対応: Sentinel、TLS、認証機能の完全サポート
- アクティブなコミュニティ: 豊富なドキュメントとサンプルコード
デメリット
- 同期処理中心: 非同期処理のサポートが限定的
- 接続管理の複雑さ: プールサイズやタイムアウト設定の最適化が必要
- Javaエコシステム限定: Java/JVM言語以外では使用不可
- 依存関係: Commons PoolやApache HTTP Client等の依存ライブラリ
- エラーハンドリング: 接続エラー時の再試行ロジックが必要
主要リンク
書き方の例
基本的な設定とMaven dependency
<!-- pom.xml -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>5.1.0</version>
</dependency>
JedisPooledを使った簡単な操作
import redis.clients.jedis.JedisPooled;
public class RedisExample {
public static void main(String[] args) {
// JedisPooledで接続(推奨方法)
JedisPooled jedis = new JedisPooled("localhost", 6379);
// 基本的な操作
jedis.set("key", "value");
String value = jedis.get("key");
System.out.println(value); // "value"
// 期限付きキー設定
jedis.setex("tempkey", 60, "temporary value"); // 60秒で有効期限切れ
// リスト操作
jedis.lpush("mylist", "element1", "element2", "element3");
List<String> list = jedis.lrange("mylist", 0, -1);
System.out.println(list);
// セット操作
jedis.sadd("myset", "member1", "member2", "member3");
Set<String> members = jedis.smembers("myset");
System.out.println(members);
}
}
JedisPoolを使った接続管理
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Jedis;
public class JedisPoolExample {
private static JedisPool pool;
static {
// プール設定
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(20); // 最大接続数
poolConfig.setMaxIdle(10); // 最大アイドル接続数
poolConfig.setMinIdle(2); // 最小アイドル接続数
poolConfig.setTestOnBorrow(true);
poolConfig.setTestOnReturn(true);
// プール初期化
pool = new JedisPool(poolConfig, "localhost", 6379, 2000, "password");
}
public void performOperations() {
// try-with-resourcesで安全な接続管理
try (Jedis jedis = pool.getResource()) {
jedis.set("pooled-key", "pooled-value");
String value = jedis.get("pooled-key");
System.out.println("Retrieved: " + value);
// 複雑な操作
jedis.hset("user:1", "name", "John Doe");
jedis.hset("user:1", "email", "[email protected]");
jedis.hset("user:1", "age", "30");
Map<String, String> user = jedis.hgetall("user:1");
System.out.println("User data: " + user);
}
}
public static void close() {
if (pool != null) {
pool.close();
}
}
}
Redis Cluster操作
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.HostAndPort;
import java.util.HashSet;
import java.util.Set;
public class ClusterExample {
public static void main(String[] args) {
// クラスタノード設定
Set<HostAndPort> jedisClusterNodes = new HashSet<>();
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7379));
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7380));
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7381));
// クラスタ接続
JedisCluster jedisCluster = new JedisCluster(jedisClusterNodes);
// クラスタでのデータ操作
jedisCluster.set("cluster-key", "cluster-value");
String value = jedisCluster.get("cluster-key");
System.out.println("Cluster value: " + value);
// 複数のキーを同じハッシュスロットに配置
jedisCluster.set("{user:1000}:profile", "user profile data");
jedisCluster.set("{user:1000}:preferences", "user preferences");
// パフォーマンスカウンタ
jedisCluster.incr("page_views");
Long views = jedisCluster.get("page_views");
System.out.println("Page views: " + views);
jedisCluster.close();
}
}
パイプライニングとトランザクション
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.Response;
public class AdvancedOperations {
public void demonstratePipelining() {
try (Jedis jedis = new Jedis("localhost", 6379)) {
// パイプライニングで複数コマンドを一括実行
Pipeline pipeline = jedis.pipelined();
Response<String> set1 = pipeline.set("pipe1", "value1");
Response<String> set2 = pipeline.set("pipe2", "value2");
Response<Long> incr = pipeline.incr("counter");
Response<List<String>> lrange = pipeline.lrange("mylist", 0, -1);
// 一括実行
pipeline.sync();
// 結果取得
System.out.println("Set result: " + set1.get());
System.out.println("Counter value: " + incr.get());
System.out.println("List contents: " + lrange.get());
}
}
public void demonstrateTransaction() {
try (Jedis jedis = new Jedis("localhost", 6379)) {
// 楽観的ロックでのトランザクション
String watchKey = "balance:1000";
jedis.watch(watchKey);
String balance = jedis.get(watchKey);
int currentBalance = Integer.parseInt(balance != null ? balance : "0");
if (currentBalance >= 100) {
Transaction tx = jedis.multi();
tx.decrBy(watchKey, 100);
tx.incrBy("balance:2000", 100);
List<Object> results = tx.exec();
if (results == null) {
System.out.println("Transaction failed due to concurrent modification");
} else {
System.out.println("Transaction successful: " + results);
}
} else {
jedis.unwatch();
System.out.println("Insufficient balance");
}
}
}
}
Pub/Subメッセージング
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
public class PubSubExample {
// カスタムメッセージリスナー
static class MessageListener extends JedisPubSub {
@Override
public void onMessage(String channel, String message) {
System.out.println("Received message: " + message + " from channel: " + channel);
}
@Override
public void onSubscribe(String channel, int subscribedChannels) {
System.out.println("Subscribed to channel: " + channel);
}
@Override
public void onUnsubscribe(String channel, int subscribedChannels) {
System.out.println("Unsubscribed from channel: " + channel);
}
@Override
public void onPMessage(String pattern, String channel, String message) {
System.out.println("Pattern message: " + message + " from " + channel + " matching " + pattern);
}
}
public static void main(String[] args) {
// Publisher
Thread publisherThread = new Thread(() -> {
try (Jedis jedis = new Jedis("localhost", 6379)) {
for (int i = 0; i < 10; i++) {
jedis.publish("news", "Breaking news #" + i);
jedis.publish("weather", "Weather update #" + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
// Subscriber
Thread subscriberThread = new Thread(() -> {
try (Jedis jedis = new Jedis("localhost", 6379)) {
MessageListener listener = new MessageListener();
jedis.subscribe(listener, "news", "weather");
}
});
subscriberThread.start();
publisherThread.start();
try {
publisherThread.join();
subscriberThread.interrupt();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
RediSearchとRedisJSONの使用
import redis.clients.jedis.JedisPooled;
import redis.clients.jedis.search.*;
import redis.clients.jedis.json.Path;
import com.google.gson.Gson;
public class ModulesExample {
static class Product {
public String name;
public String category;
public double price;
public String description;
public Product(String name, String category, double price, String description) {
this.name = name;
this.category = category;
this.price = price;
this.description = description;
}
}
public static void main(String[] args) {
JedisPooled jedis = new JedisPooled("localhost", 6379);
Gson gson = new Gson();
// RedisJSON操作
Product product = new Product("Laptop", "Electronics", 999.99, "High-performance laptop");
jedis.jsonSet("product:1", gson.toJson(product));
String productJson = jedis.jsonGet("product:1");
System.out.println("Stored product: " + productJson);
// RediSearch インデックス作成
Schema schema = new Schema()
.addTextField("name", 5.0)
.addTextField("description", 1.0)
.addTagField("category")
.addNumericField("price");
IndexDefinition def = new IndexDefinition()
.setPrefixes(new String[]{"product:"});
try {
jedis.ftCreate("product-index", IndexOptions.defaultOptions().setDefinition(def), schema);
} catch (Exception e) {
// インデックスが既に存在する場合
System.out.println("Index already exists");
}
// 検索実行
Query query = new Query("laptop")
.addFilter(new Query.NumericFilter("price", 500, 1500))
.limit(0, 10);
SearchResult result = jedis.ftSearch("product-index", query);
System.out.println("Search results: " + result.getDocuments());
jedis.close();
}
}