5.1 Jedis基本使用

2016-03-20 19:26:34 11,860 2

本节讲解如何通过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客户端

QQ截图20160320003724.png

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

QQ截图20160320004006.png

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!

 

上一篇:5.0 Jedis简介 下一篇:5.2 ShardedJedis