最近做redis的发布/订阅,出现如题所示的困扰很久,网上也很少有相关的解答。今天终于解决了,特此记录一下过程。
首先是发布类:
public class Publisher { public void publish(final Jedis jedis) { new Thread(new Runnable() { @Override public 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() {
@Override
public 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 { //取得订阅后消息的处理 @Override public void onMessage(String channel, String message) { System.out.print("onMessage:取得订阅后消息的处理 "); System.out.println(channel + "=" + message); } //取得按表达式的方式订阅的消息后的处理 @Override public void onPMessage(String pattern, String channel, String message) { System.out.print("onPMessage:取得按表达式的方式订阅的消息后的处理 "); System.out.println(pattern + "=" + channel + "=" + message); } //初始化按表达式的方式订阅时候的处理 @Override public void onPSubscribe(String pattern, int subscribedChannels) { System.out.print("onPSubscribe:初始化按表达式的方式订阅时候的处理 "); System.out.println(pattern + "=" + subscribedChannels); } //取消化按表达式的方式订阅时候的处理 @Override public void onPUnsubscribe(String pattern, int subscribedChannels) { System.out.print("onPUnsubscribe:取消化按表达式的方式订阅时候的处理 "); System.out.println(pattern + "=" + subscribedChannels); } //初始化订阅时候的处理 @Override public void onSubscribe(String channel, int subscribedChannels) { System.out.print("onSubscribe:初始化订阅时候的处理 "); System.out.println(channel + "=" + subscribedChannels); } //取消订阅时候的处理 @Override public void onUnsubscribe(String channel, int subscribedChannels) { System.out.print("onUnsubscribe:取消订阅时候的处理 "); System.out.println(channel + "=" + subscribedChannels); } }
接下来就是测试了:
//获得Jedis Jedis 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客户端哈!
相关推荐
Err:1 http://ppa.launchpad.net/ethereum/ethereum/ubuntu bionic/main amd64 bootnode amd64 1.9.10+build21009+bionic Connection timed out [IP: 91.189.95.83 80] E: Failed to fetch ...
jquery-3.1.1.min.js
在开发Vue应用时,开发者可能会遇到“net :ERR_CONNECTION_REFUSED”错误,这通常表示浏览器无法连接到指定的服务器。这个错误可能出现在多种场景下,比如本地开发环境配置不正确或者网络环境变化等。本文将重点讲解...
npm ERR! Error while executing: npm ERR! /usr/bin/git ls-remote -h -t https://github.com/nhn/raphael.git npm ERR! npm ERR! fatal: unable to access 'https://github.com/nhn/raphael.git/': Failed connect...
目前Star最多的莫属于redigo 下面是基本用法 github.com/garyburd/redigo/redis...func main() { conn,err := redis.Dial(tcp,10.1.210.69:6379) if err != nil { fmt.Println(connect redis error :,err) return
该架构已解决大部分坑,主要用于react@18.2.0移动端,在使用项目前请确保已安装node、yarn工具,node版本18+,此项目构建主要集成:axios、vant、sass、vite、sass、react V18,其中还会介绍到如何跨页面传递数据、...
这个包提供了一个易于使用的库,用于从Go语言中与Swift / Openstack Object Storage / Rackspace云文件进行接口,构建状态Go参考 安装使用go安装库 下面是文档中的一个简短示例 //创建一个连接 ...容器,err:= c.
gyp ERR! configure error gyp ERR! stack Error: EACCES: permission denied, mkdir ‘/Users/mac-pro/.nvm/versions/node/v10.16.0/lib/node_modules/webpack/node_modules/fsevents/build’ gyp ERR! System ...
对网络请求进行封装:文件目录为 network / request.js 使用方法: ...}).catch(err => { //打印错误信息 console.log(err) })。 详情参考:https://mp.csdn.net/mp_blog/creation/editor/124558480
WebApi 跨域问题主要源于浏览器的同源策略,这是一种安全机制,限制JavaScript或Cookie只能访问同一源(协议+域名+端口)下的内容。在实际开发中,当WebApi作为一个独立的服务,例如数据服务层,而MVC项目作为前端...
问题:wx.requset请求出错net::ERR_CONNECTION_RESET 源代码如下: wx.request({ url: 'https://www.dinggestyle.com/API/GetOrgList', data: { OrgType: 0 }, method: 'GET', success: function (res) { ... ...
步骤一:引入JS文件 ... 备注:支持使用 AMD/CMD 标准模块加载方法加载 步骤二:通过config接口注入权限验证配置 所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url...
<p><input type="file" id="file" name="file"/></p> <input type="button" id="btn" value="上传"/> js: [removed][removed] ... console.log('上传图片的err'); } }); }) [removed]
在Web开发中,由于浏览器的同源策略限制,JavaScript无法直接发起对不同源(协议、域名或端口)的HTTP请求。然而,Ajax技术在实现动态网页交互时常常需要跨越这个限制,这时就引入了JSONP(JSON with Padding)作为...
错误 101 (net--ERR_CONNECTION_RESET).docx
-defaults-file=/data/3306/my.cnf --basedir=/usr/local/mysql --datadir=/data/3306/data --plugin-dir=/usr/local/mysql/lib/plugin --user=mysql --log-error=/data/3306/data/xuexi.longshuai.com.err --pid-...
rtl8188eu_r16m_20161208初步验证通过_没有...[ 30.993687] hci: ERR: not support sunxi_usb_enable_ehci [ 30.999650] hci: ERR: not support sunxi_usb_enable_ohci shell@astar-evb30:/ $ shell@astar-evb30:/ $
func OnceTest2(par ...interface{})(err error) { res := par[2].(context.Context) for{ select { case (): log.Println("停止了!") return default: log.Println("只执行一次") time.Sleep...
npm ERR! Error while executing: npm ERR! /usr/bin/git ls-remote -h -t https://github.com/nhn/raphael.git npm ERR! npm ERR! fatal: unable to access 'https://github.com/nhn/raphael.git/': Failed connect...
在Google chrome开发人员控制台中一直报此错误。(虽然只是一个警告,但是体验还是非常不好) 先说解决方案: 第一种: 在Google chrome浏览器调试工具中,设置该调试工具,点开之后选择Settings ...