5.1 Jedis基本使用
本节讲解如何通过Jedis来操作Redis中的各种数据类型
1、Jedis操作Redis各种数据结构案例
import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.junit.BeforeClass; import org.junit.Test; import redis.clients.jedis.Jedis; public class JedisTest { static Jedis jedis; @BeforeClass public static void beforeClass() { jedis = new Jedis("115.28.65.149"); } // Redis和Java字符串实例 @Test public void testString() { // set the data in redis string jedis.set("tutorial-name", "Redis tutorial"); // Get the stored data and print it System.out.println("Stored string in redis:: "+ jedis.get("tutorial-name")); // 输出:Stored string in redis:: Redis tutorial } //Redis和Java列表示例 @Test public void testList() { jedis.lpush("tutorial-list", "Redis"); jedis.lpush("tutorial-list", "Mongodb"); jedis.lpush("tutorial-list", "Mysql"); // Get the stored data and print it List<String> list = jedis.lrange("tutorial-list", 0, 5); for (int i = 0; i < list.size(); i++) { System.out.println("Stored string in redis:: " + list.get(i)); } /*输出 Stored string in redis:: Mysql Stored string in redis:: Mongodb Stored string in redis:: Redis */ } //Redis和Java的键实例 @Test public void testKeys(){ Set<String> keys = jedis.keys("*"); for (String key : keys) { System.out.println("List of stored keys:: " + key); } /*输出 List of stored keys:: tutorial-name List of stored keys:: tutorial-list */ } //Redis和Java的hash实例 @Test public void testHash(){ String key="user"; String field_name="name"; String field_name_value="tianshouzhi"; String field_city="city"; String field_city_value="shanghai"; jedis.hset(key, field_name, field_name_value); jedis.hset(key, field_city, field_city_value); Map<String, String> map = jedis.hgetAll(key); Set<Entry<String,String>> entrySet = map.entrySet(); for (Entry<String, String> entry : entrySet) { System.out.println(entry.getKey()+":"+entry.getValue()); } /* * 输出 * name:tianshouzhi * city:shanghai */ } //Redis和Java的集合实例 @Test public void testSet(){ String key="set_key"; String[] members=new String[]{"a","b","a","c"}; jedis.sadd(key, members); Set<String> smembers = jedis.smembers(key); for (String string : smembers) { System.out.println(string); } /* * 输出 * name:tianshouzhi * city:shanghai */ } // Redis和Java的集合实例 @Test public void testZSet() { String key = "zset_key"; Map<String,Double> scoreMembers=new HashMap<String, Double>(){{ put("tianshouzhi", 1.0); put("huhuamin", 2.0); }}; jedis.zadd(key, scoreMembers); Set<String> zrange = jedis.zrange(key, 0, 2); for (String member : zrange) { System.out.println(member); System.out.println(jedis.zscore(key, member)); } /* * 输出 * tianshouzhi 1.0 huhuamin 2.0 */ } }
2、Jedis 通知
//订阅:需要先执行订阅操作 //覆盖JedisPubSub中的onMessage,用于回调 @Test public void testSubsribe() { JedisPubSub jedisPubSub = new JedisPubSub() { @Override public void onMessage(String channel, String message) { System.out.println(channel); System.out.println(message); } }; jedis.subscribe(jedisPubSub, "channel1"); /*输出 channel1 test publish substribe*/ } //发布 @Test public void testPublish(){ String channel="channel1"; String message="test publish substribe"; jedis.publish(channel, message); }
订阅一个channel,需要先用一个client来订阅。然后再publish消息到这个channel中,所以我们需要先执行testSubsribe,再执行testPublish。需要注意的是,JedisPubSub
是在后台运行的,因此可以重复不断的接受消息。
需要注意的是,因为发布订阅模型中,一条消息被所有订阅次channel的client接受到。有的业务场景下,可能不满足我们要的要求,例如处理订单,我们可能只需要一个Client来处理。此时我们需要使用到阻塞队列。
3、阻塞队列
为了演示阻塞队列的功能,我们启动2个客户端,一个是java客户端,一个是redis-cli客户端,都从列表queue中使用brpop获取数据。
redis-cli客户端
Java客户端
@Test public void testBlockedQueue(){ List<String> brpop = jedis.brpop(0,"queue"); for (String string : brpop) { System.out.println(string); } }
运行这个测试方法,也会进入阻塞状态。
往queue中放入消息
@Test public void testLpush(){ jedis.lpush("queue", "queue_message1","queue_message2"); }
执行这段代码,我们将会看到两个客户端分别接受到了一条消息,而不是每条消息被共享。
redis-cli接受到queue_message1
Java客户端接受到
queue queue_message2
需要注意的是,阻塞队列接受到一条消息之后,就会跳出阻塞状态。如果需要不断的循环监听,则要使用while(true)将这段代码包含起来,如
//阻塞队列 @Test public void testBlockedQueue(){ while(true){ List<String> brpop = jedis.brpop(0,"queue"); for (String string : brpop) { System.out.println(string); } } }
此时,我们在执行testLpush方法,看到控制台输出
queue queue_message1 queue queue_message2
从现实的结果中,我们可以看出以下这段代码的返回值的组成
List<String> brpop = jedis.brpop(0,"queue");
List中的元素总是偶数个,其中奇数表示的从哪一个队列中监听到的消息,偶数表示消息的内容。
使用 pipeline
如果希望一次发送一批 redis 命令,一种有效的方式是使用 pipeline。
jedis 使用 pipeline 的代码如下:
Pipeline p = jedis.pipelined(); p.set("fool", "bar"); p.zadd("foo", 1, "barowitch"); p.zadd("foo", 0, "barinsky"); p.zadd("foo", 0, "barikoviev"); Response<String> pipeString = p.get("fool"); Response<Set<String>> sose = p.zrange("foo", 0, -1); p.sync(); int soseSize = sose.get().size(); Set<String> setBack = sose.get();
使用 transaction
如果希望一些命令一起执行而不被干扰,可以通过 transaction 将命令打包到一起执行:
jedis.watch (key1, key2, ...); BinaryTransaction t = jedis.multi(); t.set("foo", "bar"); t.exec();
如果需要得到返回值,可以参考下面的代码:
Transaction t = jedis.multi(); t.set("fool", "bar"); Response<String> result1 = t.get("fool"); t.zadd("foo", 1, "barowitch"); t.zadd("foo", 0, "barinsky"); t.zadd("foo", 0, "barikoviev"); Response<Set<String>> sose = t.zrange("foo", 0, -1); // get the entire sortedset t.exec(); // dont forget it String foolbar = result1.get(); // use Response.get() to retrieve things from a Response int soseSize = sose.get().size(); // on sose.get() you can directly call Set methods!