JedisDataException: ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in thi
来源:互联网 发布:淘宝寄到澳洲 编辑:程序博客网 时间:2024/04/25 06:44
最近做redis的发布/订阅,出现如题所示的困扰很久,网上也很少有相关的解答。今天终于解决了,特此记录一下过程。
首先是发布类:
public class Publisher {public void publish(final Jedis jedis) {new Thread(new Runnable() {@Overridepublic void run() {System.out.println("开始发布讯息咯:");//String channel = jedis.get("channel");//String message = jedis.get("300C00");//System.out.println("[取到]:" + channel + "," + message);try { Thread.currentThread().sleep(2000); } catch (InterruptedException e) { e.printStackTrace();}//jedis.publish(String channel, String message)jedis.publish("D00C003", "oklalllla"); jedis.publish("hello", "oklalllla");}}).start();;}}
订阅类:
public class Subscriber1 {public void sub(final Jedis jedis, final MyListener1 listener) {new Thread(new Runnable() {@Overridepublic void run() {System.out.println("订阅到讯息……");//subscribe(JedisPubSub, String[] channels)或psubscribe(JedisPubSub, String[] patterns)jedis.subscribe(listener, new String[]{"300C00", "news.share"});} }).start();}}
订阅类依赖的监听类,该监听类表明一旦接收到发布消息后的处理。需继承JeidsPubSub基类:
public class MyListener1 extends JedisPubSub {//取得订阅后消息的处理@Overridepublic void onMessage(String channel, String message) {System.out.print("onMessage:取得订阅后消息的处理");System.out.println(channel + "=" + message); }//取得按表达式的方式订阅的消息后的处理@Overridepublic void onPMessage(String pattern, String channel, String message) {System.out.print("onPMessage:取得按表达式的方式订阅的消息后的处理 ");System.out.println(pattern + "=" + channel + "=" + message);}//初始化按表达式的方式订阅时候的处理@Overridepublic void onPSubscribe(String pattern, int subscribedChannels) {System.out.print("onPSubscribe:初始化按表达式的方式订阅时候的处理 ");System.out.println(pattern + "=" + subscribedChannels); }//取消化按表达式的方式订阅时候的处理@Overridepublic void onPUnsubscribe(String pattern, int subscribedChannels) {System.out.print("onPUnsubscribe:取消化按表达式的方式订阅时候的处理 ");System.out.println(pattern + "=" + subscribedChannels); }//初始化订阅时候的处理@Overridepublic void onSubscribe(String channel, int subscribedChannels) {System.out.print("onSubscribe:初始化订阅时候的处理 ");System.out.println(channel + "=" + subscribedChannels); }//取消订阅时候的处理@Overridepublic void onUnsubscribe(String channel, int subscribedChannels) {System.out.print("onUnsubscribe:取消订阅时候的处理 ");System.out.println(channel + "=" + subscribedChannels);}}
接下来就是测试了:
//获得JedisJedis jedis1 = JedisFactory.getJedis();Jedis jedis2 = JedisFactory.getJedis();MyListener2 listener = new MyListener2(); //发布 channel message Publisher2 publisher = new Publisher2(); publisher.publish(jedis2); //订阅 Subscriber1 scribe = new Subscriber1(); scribe.sub(jedis1, listener);
JedisFactory:
public class JedisFactory {private static Jedis jedis;static { // 池基本配置 JedisPoolConfig config = new JedisPoolConfig(); config.setMaxIdle(5); config.setMaxWaitMillis(1000l); config.setTestOnBorrow(false); // slave链接 // List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>(); // shards.add(new JedisShardInfo("127.0.0.1", 6379, "master")); // 构造池 JedisPool pool = new JedisPool(config,"127.0.0.1",6379, 100000); //容忍的超时时间 jedis = pool.getResource();}public static Jedis getJedis() {return jedis;}}
运行之后,出现如题所示的异常:
redis.clients.jedis.exceptions.JedisDataException: ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context
at redis.clients.jedis.Protocol.processError(Protocol.java:104)
at redis.clients.jedis.Protocol.process(Protocol.java:122)
at redis.clients.jedis.Protocol.read(Protocol.java:191)
at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:175)
at redis.clients.jedis.Jedis.set(Jedis.java:54)
该异常的表面意思是说Jedis的发布与订阅数据出现了异常,并且说只有指定的情况在上下文中。不太好理解,查阅底层API发现发布、订阅的语法都没有错,被困扰了N久!!!
后发现问题出在自己写的JeidsFactory。我写JedisFactory的本意是封装获取Jedis对象的代码,但不知不觉地,getJedis()方法是单例的,即尽管发布和订阅分别调用了该方法,但获取到的永远是同一个Jedis对象。所以报错……(为什么发布、订阅不能使用同一个Jedis,我也不知道原因。。)
遂改成:
static JedisPool pool;static { // 池基本配置 JedisPoolConfig config = new JedisPoolConfig(); config.setMaxIdle(5); config.setMaxWaitMillis(1000l); config.setTestOnBorrow(false); // slave链接 // List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>(); // shards.add(new JedisShardInfo("127.0.0.1", 6379, "master")); // 构造池 pool = new JedisPool(config,"127.0.0.1",6379, 100000); //容忍的超时时间 }
发布和订阅再从pool中取,即可:
Jedis jedis1 = pool.getResource();Jedis jedis2 = pool.getResource();
执行顺序:
发布讯息->订阅讯息->on(P)Subscribe->on(P)Message(当通过psubscribe的方式订阅时,就走onPSubscribe、onPMessage)
所以,当你发现自己出现这个问题,而发布订阅的语法又没错时,可以看看是不是问题出在这儿!——发布、订阅要使用不同的redis客户端哈!
- JedisDataException: ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in thi
- No P.O. Box Allowed in Billing or Shipping Address
- p;
- p
- p
- p
- p
- P
- :-P
- p
- p++
- p**
- *p++,(*p)++,*++p,++*p
- *p++, *++p, ++*p, (*p)++
- P
- *p++
- *p++, ++*p, (*p)++, *++p
- P
- Windows下Kettle-7.0集群安装
- ....快排+链表
- 城市问题(Floyd)
- Hibernate与Oracle应用之主键生成
- springMVC+Mybatis框架搭建与 事务管理
- JedisDataException: ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in thi
- Hibernate之对象关系映射基础
- python与集体智慧编程学习
- 用hibernate的HQL(面向对象的查询语言)实现模糊查询的3种方式
- redis主从复制之linux环境配置
- Mac环境下安装运行splash
- PAT 1017. Queueing at Bank (25)
- Cannot find the definition(implementation) of this function
- hibernate向Oracle写入数据step by step