Intro to Jedis – the Java Redis Client Library
转自:http://www.baeldung.com/jedis-java-redis-client-library
1. Overview
This article is an introduction to Jedis, a client library in Java for Redis – the popular in-memory data structure store that can persist on disk as well. It is driven by a keystore-based data structure to persist data and can be used as a database, cache, message broker, etc.
First, we are going to explain in which kind of situations Jedis is useful and what it is about.
In the subsequent sections we are elaborating on the various data structures and explaining transactions, pipelining and the publish/subscribe feature. We conclude with connection pooling and Redis Cluster.
2. Why Jedis?
Redis lists the most well-known client libraries on their official site. There are multiple alternatives to Jedis, but only two more are currently worthy of their recommendation star, lettuce, and Redisson.
These two clients do have some unique features like thread safety, transparent reconnection handling and an asynchronous API, all features of which Jedis lacks.
However, it is small and considerably faster than the other two. Besides, it is the client library of choice of the Spring Framework developers and it has the biggest community of all three.
3. Maven Dependencies
Let’s start by declaring the only dependency we will need in the pom.xml:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.1</version>
</dependency>
If you’re looking for the latest version of the library, check out this page.
4. Redis Installation
You will need to install and fire up one of the latest versions of Redis. We are running the latest stable version at this moment (3.2.1), but any post 3.x version should be okay.
Find here more information about Redis for Linux and Macintosh, they have very similar basic installation steps. Windows is not officially supported but this port is well maintained.
Thereafter we can directly dive in and connect to it from our Java code:
Jedis jedis = new Jedis();
The default constructor will work just fine unless you have started the service on a non-default port or on a remote machine, in which case you can configure it correctly by passing the correct values as parameters into the constructor.
5. Redis Data Structures
Most of the native operation commands are supported and, conveniently enough, they normally share the same method name.
5.1. Strings
Strings are the most basic kind of Redis value, useful for when you need to persist simple key-value data types:
jedis.set("events/city/rome", "32,15,223,828");
String cachedResponse = jedis.get("events/city/rome");
The variable cachedResponse will hold the value 32,15,223,828. Coupled with expiration support, discussed later, it can work as a lightning fast and simple to use cache layer for HTTP requests received at your web application and other caching requirements.
5.2. Lists
Redis Lists are simply lists of strings, sorted by insertion order and make it an ideal tool to implement, for instance, message queues:
jedis.lpush("queue#tasks", "firstTask");
jedis.lpush("queue#tasks", "secondTask");
String task = jedis.rpop("queue#tasks");
5.3. Sets
Redis Sets are an unordered collection of Strings that come in handy when you want to exclude repeated members:
jedis.sadd("nicknames", "nickname#1");
jedis.sadd("nicknames", "nickname#2");
jedis.sadd("nicknames", "nickname#1");
Set<String> nicknames = jedis.smembers("nicknames");
boolean exists = jedis.sismember("nicknames", "nickname#1");
The Java Set nicknames will have a size of 2, the second addition of nickname#1 was ignored. Also, the exists variable will have a value of true, the method sismember enables you to quickly check for the existence of a particular member.
5.4. Hashes
Redis Hashes are mapping between String fields and String values:
jedis.hset("user#1", "name", "Peter");
jedis.hset("user#1", "job", "politician");
String name = jedis.hget("user#1", "name");
Map<String, String> fields = jedis.hgetAll("user#1");
String job = fields.get("job");
As you can see, hashes are a very convenient data type when you want to access object’s properties individually since you do not need to retrieve the whole object.
5.5. Sorted Sets
Sorted Sets are like a Set where each member has an associated ranking, that is used for sorting them:
Map<String, Double> scores = new HashMap<>();
scores.put("PlayerOne", 3000.0);
scores.put("PlayerTwo", 1500.0);
scores.put("PlayerThree", 8200.0);
scores.keySet().forEach(player -> {
jedis.zadd("ranking", scores.get(player), player);
});
String player = jedis.zrevrange("ranking", 0, 1).iterator().next();
long rank = jedis.zrevrank("ranking", "PlayerOne");
The variable player will hold the value PlayerThree because we are retrieving the top 1 player and he is the one with the highest score. The rank variable will have a value of 1 because PlayerOne is the second in the ranking and the ranking is zero-based.
6. Transactions
Transactions guarantee atomicity and thread safety operations, which means that requests from other clients will never be handled concurrently during Redis transactions:
String friendsPrefix = "friends#";
String userOneId = "4352523";
String userTwoId = "5552321";
Transaction t = jedis.multi();
t.sadd(friendsPrefix + userOneId, userTwoId);
t.sadd(friendsPrefix + userTwoId, userOneId);
t.exec();
You can even make a transaction success dependent on a specific key by “watching” it right before you instantiate your Transaction:
jedis.watch("friends#deleted#" + userOneId);
If the value of that key changes before the transaction is executed, the transaction will not be completed successfully.
7. Pipelining
When we have to send multiple commands, we can pack them together in one request and save connection overhead by using pipelines, it is essentially a network optimization. As long as the operations are mutually independent, we can take advantage of this technique:
String userOneId = "4352523";
String userTwoId = "4849888";
Pipeline p = jedis.pipelined();
p.sadd("searched#" + userOneId, "paris");
p.zadd("ranking", 126, userOneId);
p.zadd("ranking", 325, userTwoId);
Response<Boolean> pipeExists = p.sismember("searched#" + userOneId, "paris");
Response<Set<String>> pipeRanking = p.zrange("ranking", 0, -1);
p.sync();
String exists = pipeExists.get();
Set<String> ranking = pipeRanking.get();
Notice we do not get direct access to the command responses, instead we are given a Responseinstance from which we can request the underlying response after the pipeline has been synced.
8. Publish/Subscribe
We can use the Redis messaging broker functionality to send messages between the different components of our system. Make sure the subscriber and publisher threads do not share the same Jedis connection.
8.1. Subscriber
Subscribe and listen to messages sent to a channel:
Jedis jSubscriber = new Jedis();
jSubscriber.subscribe(new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
// handle message
}
}, "channel");
Subscribe is a blocking method, you will need to unsubscribe from the JedisPubSub explicitly. We have overridden the onMessage method but there are many more useful methods available to override.
8.2. Publisher
Then simply send messages to that same channel from the publisher’s thread:
Jedis jPublisher = new Jedis();
jPublisher.publish("channel", "test message");
9. Connection Pooling
It is important to know that the way we have been dealing with our Jedis instance is naive. In a real world scenario, you do not want to use a single instance in a multi-threaded environment as a single instance is not thread safe.
Luckily enough we can easily create a pool of connections to Redis for us to reuse on demand, a pool that is thread safe and reliable as long as you return the resource to the pool when you are done with it.
Let’s create the JedisPool:
final JedisPoolConfig poolConfig = buildPoolConfig();
JedisPool jedisPool = new JedisPool(poolConfig, "localhost");
private JedisPoolConfig buildPoolConfig() {
final JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(128);
poolConfig.setMaxIdle(128);
poolConfig.setMinIdle(16);
poolConfig.setTestOnBorrow(true);
poolConfig.setTestOnReturn(true);
poolConfig.setTestWhileIdle(true);
poolConfig.setMinEvictableIdleTimeMillis(Duration.ofSeconds(60).toMillis());
poolConfig.setTimeBetweenEvictionRunsMillis(Duration.ofSeconds(30).toMillis());
poolConfig.setNumTestsPerEvictionRun(3);
poolConfig.setBlockWhenExhausted(true);
return poolConfig;
}
Since the pool instance is thread safe, you can store it somewhere statically but you should take care of destroying the pool to avoid leaks when the application is being shutdown.
Now we can make use of our pool from anywhere in the application when needed:
try (Jedis jedis = jedisPool.getResource()) {
// do operations with jedis resource
}
We used the Java try-with-resources statement to avoid having to manually close the Jedis resource, but if you cannot use this statement you can also close the resource manually in the finally clause.
Make sure you use a pool like we have described in your application if you do not want to face nasty multi-threading issues. You can obviously play with the pool configuration parameters to adapt it to the best setup in your system.
10. Redis Cluster
This Redis implementation provides easy scalability and high availability, we encourage you to read their official specification if you are not familiar with it. We will not cover Redis cluster setup since that is a bit out of the scope for this article, but you should have no problems in doing so when you are done with its documentation.
Once we have that ready, we can start using it from our application:
try (JedisCluster jedisCluster = new JedisCluster(new HostAndPort("localhost", 6379))) {
// use the jedisCluster resource as if it was a normal Jedis resource
} catch (IOException e) {}
We only need to provide the host and port details from one of our master instances, it will auto-discover the rest of the instances in the cluster.
This is certainly a very powerful feature but it is not a silver bullet. When using Redis Cluster you cannot perform transactions nor use pipelines, two important features on which many applications rely for ensuring data integrity.
Transactions are disabled because, in a clustered environment, keys will be persisted across multiple instances. Operation atomicity and thread safety cannot be guaranteed for operations that involve command execution in different instances.
Some advanced key creation strategies will ensure that data that is interesting for you to be persisted in the same instance will get persisted that way. In theory, that should enable you to perform transactions successfully using one of the underlying Jedis instances of the Redis Cluster.
Unfortunately, currently you cannot find out in which Redis instance a particular key is saved using Jedis (which is actually supported natively by Redis), so you do not know which of the instances you must perform the transaction operation. If you are interested about this, you can find more information here.
11. Conclusion
The vast majority of the features from Redis are already available in Jedis and its development moves forward at a good pace.
It gives you the ability to integrate a powerful in-memory storage engine in your application with very little hassle, just do not forget to set up connection pooling to avoid thread safety issues.
You can find code samples in the GitHub project.
Intro to Jedis – the Java Redis Client Library的更多相关文章
- Apache Curator is a Java/JVM client library for Apache ZooKeeper
http://curator.apache.org/index.html Welcome to Apache Curator What is Curator? Curator n ˈkyoor͝ˌāt ...
- java redis client jedis 测试及常用命令
package cn.byref.demo1; import java.util.HashMap;import java.util.List;import java.util.Map;import j ...
- java redis client jedis 测试
package cn.byref.demo1; import java.util.HashMap; import java.util.List; import java.util.Map; impor ...
- Redis错误:jedis.exceptions.JedisDataException: ERR Client sent AUTH, but no password is set
原文链接:http://blog.csdn.net/rchm8519/article/details/48347797 redis.clients.util.Pool.getResource(Pool ...
- Redis面向java的Client
一.概念简介: Redis: Redis是一款开源的Key-Value数据库,运行在内存中,由ANSI C编写,详细的信息在Redis官网上面有,因为我自己通过google等各种渠道去学习Redis, ...
- (转)java redis使用之利用jedis实现redis消息队列
应用场景 最近在公司做项目,需要对聊天内容进行存储,考虑到数据库查询的IO连接数高.连接频繁的因素,决定利用缓存做. 从网上了解到redis可以对所有的内容进行二进制的存储,而java是可以对所有对象 ...
- Redis入门 – Jedis存储Java对象 - (Java序列化为byte数组方式)
Redis入门 – Jedis存储Java对象 - (Java序列化为byte数组方式) 原文地址:http://alanland.iteye.com/admin/blogs/1600685(欢迎转载 ...
- redis.clients.jedis.exceptions.JedisDataException: ERR Client sent AUTH, but no password is set
使用哨兵模式连接redis连接池时,遇到错误: Caused by: redis.clients.jedis.exceptions.JedisDataException: ERR Client sen ...
- Java Redis 连接池 Jedis 工具类
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import redis.clients.jedis.Jedis; import re ...
随机推荐
- JAVA Socket通信 打造属于自己的网盘
近一个月没敲JAVA代码了,最近老师布置了一个写JAVA网盘的作业,总共花了十几个小时,总算写完了,debug真的累,感觉自己还是菜了,没有那种有一个想法就能马上用代码实现的能力....不扯了,下面开 ...
- 【原创】ABP之IConventionalDependencyRegistra接口分析
类图: 作用: abp中默认把对象的注册分为5中约定注册方式: 1.AbpAspNetCoreConventionalRegistrar public class AbpAspNetCoreConve ...
- 第01章 准备工作.md
第1章 准备工作 1.1 本书的内容 本书讲的是利用Python进行数据控制.处理.整理.分析等方面的具体细节和基本要点.我的目标是介绍Python编程和用于数据处理的库和工具环境,掌握这些,可以让你 ...
- Linux虚拟机上安装redis
1.检查安装依赖程序 yum install gcc-c++ yum install -y tcl yum install wget 2.获取安装文件 wget http://download.red ...
- Python HTTP 请求时对重定向中的 cookie 的处理
首先说明一下,我使用的是 Python3 的 urllib,但 Python2.x 同理(使用 urllib2). 想用脚本去登录一个网站.和很多网站一样,该网站使用 cookie 来保存会话信息.这 ...
- php get_magic_quotes_gpc()函数使用
magic_quotes_gpc函数在php中的作用是判断解析用户提示的数据,如包括有:post.get.cookie过来的数据增加转义字符"\",以确保这些数据不会引起程序,特别 ...
- 20172302 《Java软件结构与数据结构》第四周学习总结
2018年学习总结博客总目录:第一周 第二周 第三周 第四周 教材学习内容总结 第六章 列表 1.列表是对象的有序集合,在 List 界面中定义. List 接口表示集合框架中的列表.列表可以具有重复 ...
- restful开发API
http://blog.csdn.net/kkkloveyou/article/details/21391033 小示例http://blog.csdn.net/u011645059/article/ ...
- python 数字
python数字: 本文主要讲解常用的数字类型转换, 数字函数和随机数字函数. # coding:utf-8 # python数字类型转换 def data_conversion(): "& ...
- Revit API 创建带箭头的标注
[Transaction(TransactionMode.Manual)] [Regeneration(RegenerationOption.Manual)] public class cmd : ...