IBM Websphere MQ 使用详解

本文围绕MQ展开,介绍了MQ的安装配置,可参考相关链接。阐述了队列对应Buffer、通道对应Channel的原理,以及远程队列与本地队列的消息传递。还给出Java代码,包括阻塞模式下的初始化、消息参数设置,以及测试类中常见问题及原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.MQ安装配置

安装和配置的内容,可参考https://jingyan.baidu.com/article/2fb0ba409f4e1e00f2ec5fd3.html
下面是安装配置后的截图:
IBM MQ 部署后截图

2.队列和通道的理解

队列对应Buffer,通道对应Channel。
根据通道是本方还是对方,启用相应的通道(即服务)。
MQ队列
远程队列_remote发送到对方的本地队列_local。
比如,在abc_remote上放入消息“123”,在cz_local队列上就能获取“123”。

更详细的理解请点击

3.java代码

3.1 阻塞模式
import grp.pt.util.StringUtil;

import org.apache.log4j.Logger;

import com.ibm.mq.MQC;
import com.ibm.mq.MQEnvironment;
import com.ibm.mq.MQException;
import com.ibm.mq.MQGetMessageOptions;
import com.ibm.mq.MQMessage;
import com.ibm.mq.MQPutMessageOptions;
import com.ibm.mq.MQQueue;
import com.ibm.mq.MQQueueManager;
import com.ibm.mq.MQSimpleConnectionManager;
import com.river.common.UploadFileUtil;

/**
 * MQ配置 连接信息
 */
public class MqHandler {

	private static Logger log = Logger.getLogger(MqHandler.class);

	private static String MQ_IP = UploadFileUtil
			.getFromPro("mqconfig", "MQ_IP");

	private static int MQ_PORT = Integer.parseInt(UploadFileUtil.getFromPro(
			"mqconfig", "MQ_PORT"));
	// 队列管理器
	private static String MQ_QMANAGER = UploadFileUtil.getFromPro("mqconfig",
			"MQ_QMANAGER");
	// mq服务方通道
	private static String MQ_CHANNEL = UploadFileUtil.getFromPro("mqconfig",
			"MQ_CHANNEL");
	// mq通讯编码集
	private static int MQ_CCSID = Integer.parseInt(UploadFileUtil.getFromPro(
			"mqconfig", "MQ_CCSID"));
	// mq请求方发送队列
	private static String MQ_CLENT_SENDQUEUE = UploadFileUtil.getFromPro(
			"mqconfig", "MQ_CLENT_SENDQUEUE");
	// mq请求方接收队列
	private static String MQ_CLENT_RECQUEUE = UploadFileUtil.getFromPro(
			"mqconfig", "MQ_CLENT_RECQUEUE");
	
	// MQ自带连接池
	private static MQSimpleConnectionManager myConnMan = null;
	
	// 异步长连接接收队列管理器
	private MQQueueManager queueManager = null;

	// 异步发送队列
	private MQQueue SendQueue = null;
	// 异步接收队列
	public MQQueue ReceiveQueue = null;
	
	/**
	 * 构造方法
	 */
	public MqHandler() throws Exception {
		init();
	}

	/**
	 * 异步发送消息
	 * 
	 * @param msg
	 * @param messageId
	 * @param charSet
	 * @throws Exception
	 */
	public void sendMsg(String msg, String messageId, String charSet)
			throws Exception {

		try {

			if (StringUtil.isEmpty(charSet)) {
				charSet = "GBK";
			}

			byte[] msgId = StringUtil.isEmpty(messageId) ? null : messageId
					.getBytes(charSet);

			// 打开队列
			queueManager = new MQQueueManager(MQ_QMANAGER, myConnMan);
			SendQueue = queueManager.accessQueue(MQ_CLENT_SENDQUEUE,
					MQC.MQOO_OUTPUT | MQC.MQPMO_NEW_MSG_ID
							| MQC.MQOO_FAIL_IF_QUIESCING, null, null, null);

			// 初始化消息选项
			MQPutMessageOptions pmo = new MQPutMessageOptions();
			// 确保每次发送前为消息自动生成唯一的msgId
			pmo.options = pmo.options + MQC.MQPMO_NEW_MSG_ID;
			// 如果设置了该参数,则发送后必须调用commit功能。否则无法将消息发送出
			pmo.options = pmo.options + MQC.MQPMO_SYNCPOINT;

			// 创建消息对象
			MQMessage outMsg = new MQMessage();
			// 设置MQMD格式字段
			outMsg.format = MQC.MQFMT_STRING;

			outMsg.messageId = msgId == null ? MQC.MQMI_NONE : msgId;

			outMsg.encoding = MQ_CCSID;
			outMsg.characterSet = MQ_CCSID;

			// 消息发送时必须以字节流的方式发送
			outMsg.write(msg.getBytes(charSet));

			// 在队列上放置消息
			SendQueue.put(outMsg, pmo);

			// 和MQC.MQPMO_SYNCPOINT属性对应。如果设置了该属性,则发送后需要提交。
			queueManager.commit();

		} finally {
			close(SendQueue);
		}

	}

	/**
	 * 接收消息
	 * @param correlationId
	 * @param charSet
	 * @return
	 * @throws Exception
	 */
	public String receive(String correlationId, String charSet)
			throws Exception {

		try {
			if (StringUtil.isEmpty(charSet)) {
				charSet = "GBK";
			}
			
			queueManager = new MQQueueManager(MQ_QMANAGER, myConnMan);
			ReceiveQueue = queueManager.accessQueue(MQ_CLENT_RECQUEUE,
					MQC.MQOO_INPUT_AS_Q_DEF | MQC.MQOO_INQUIRE
							| MQC.MQOO_FAIL_IF_QUIESCING);

			MQMessage respMessage = new MQMessage();

			// 设置MQMD 格式字段
			respMessage.format = MQC.MQFMT_STRING;
			// 设置编码格式与MQ服务一致
			respMessage.encoding = MQ_CCSID;
			// 设置字符集与MQ服务一致
			respMessage.characterSet = MQ_CCSID;

			MQGetMessageOptions gmo = new MQGetMessageOptions();

			gmo.options = gmo.options + MQC.MQGMO_WAIT; // 如果设置了该参数,则当前线程将阻塞,直到等到回复的消息或超时
			gmo.waitInterval = MQC.MQWI_UNLIMITED;
			if (StringUtil.isNotEmpty(correlationId)) {
				// 如果设置了该参数,则根据消息的correlId去匹配对应的响应消息
				gmo.matchOptions = MQC.MQMO_MATCH_CORREL_ID;
				respMessage.correlationId = correlationId.getBytes(charSet);
			}

			ReceiveQueue.get(respMessage, gmo);

			byte[] msgBuffer = new byte[respMessage.getMessageLength()];

			respMessage.readFully(msgBuffer);

			String respMsg = new String(msgBuffer, charSet);

			return respMsg;
		} finally {
			close(ReceiveQueue);
		}
	}

	/**
	 * 初始化连接
	 * 
	 * @param type
	 * @throws MQException
	 */
	private void init() throws MQException {
		MQEnvironment.hostname = MQ_IP;
		MQEnvironment.port = MQ_PORT;
		MQEnvironment.CCSID = MQ_CCSID;
		MQEnvironment.channel = MQ_CHANNEL;
		MQEnvironment.properties.put(MQC.TRANSPORT_PROPERTY,
				MQC.TRANSPORT_MQSERIES_CLIENT);
		
		myConnMan = new MQSimpleConnectionManager();
        myConnMan.setActive(MQSimpleConnectionManager.MODE_AUTO);
        myConnMan.setTimeout(3600000);
        myConnMan.setMaxConnections(75);
        myConnMan.setMaxUnusedConnections(50);
        MQEnvironment.setDefaultConnectionManager(myConnMan);
        
		log.info("初始化队列管理器receiverQueueManager....." + MQ_QMANAGER);
	}

	private void close(MQQueue queue) {

		try {
			if (queue != null && queue.isOpen) {
				queue.close();
			}

			if (queueManager != null) {
				queueManager.disconnect();
			}

		} catch (MQException ex) {
			log.error("", ex);
		}
	}
}

网上类似的代码很多,下面对代码中的细节进行解释。
初始化
MQEnvironment的静态属性:hostname、port、CCSID等初始化后,MQQueueManager利用这些属性来构造实例对象。
MQSimpleConnectionManager是简单的连接池,当设置了连接池后MQEnvironment.setDefaultConnectionManager(myConnMan),再使用close方法时,并不会破坏连接,而是归还池中。

连接池详细内容可以参考官方的API

消息参数

  • MQOO_FAIL_IF_QUIESCING
    如果队列管理器停顿就取不到消息
  • MQOO_INPUT_AS_Q_DEF
    读取后消息从队列中移除,与之相对的是MQOO_BROWSE,读取后消息还在。
  • MQGMO_WAIT
    当队列中没有消息时,等待有消息时才返回。相当于阻塞IO。
  • MQWI_UNLIMITED
    无限等待时间,必须设置了waitInterval.xxx并和上条属性结合才能起到阻塞的效果。这个等待时间可为任意值。
  • MQOO_INQUIRE
    如果需要获取队列深度等信息的时候,就要加上此参数。
  • MQPMO_NEW_MSG_ID
    确保每次发送前为消息自动生成唯一的msgId。
  • MQPMO_SYNCPOINT
    如果设置了该参数,则发送后必须调用commit功能。否则无法将消息发送出。queueManager.commit()。

更多参数参见官方说明

3.2测试类
import org.jfree.util.Log;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import com.ctjsoft.treasury.util.MqHandler;

@RunWith(JUnit4.class)
public class MqTest {
	
	@Test
	public void mqSend(){
		try {
			MqHandler mq = new MqHandler();
			mq.sendMsg("sq--send1", null, "gbk");
			mq.sendMsg("sq--send2", null, "gbk");
			mq.sendMsg("sq--send3", null, "gbk");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	@Test
	public void mqReceive(){
		try {
			MqHandler mq = new MqHandler();
			String msg = mq.receive(null, "gbk");
			System.out.println(msg);
			String msg1 = mq.receive(null, "gbk");
			System.out.println(msg1);
			String msg2 = mq.receive(null, "gbk");
			System.out.println(msg2);
			System.out.println("任务完成");
		} catch (Exception e) {
			Log.error("", e);
		}
	}

}

测试过程中出现的问题举例:

  • MQJE001: 完成代码是 2,原因为 2033
    当前消息队列为空,如果不是阻塞模式的获取消息,队列为空就会抛出此异常。
  • MQJE001: MQException 出现:完成代码是 2,原因为 2018
    MQJI002: 未连接至队列管理器。

    消息通道服务被关闭
  • 原因为 2080
    代表消息的实际长度超过了你在程序代码中设置的缓冲区长度

感觉有用请点赞

目录 目录 2 前言 9 本书范围 9 本书读者 9 进一步参考资料 10 第一部分 Websphere MQ原理和体系结构 11 第一章Websphere MQ原理 11 目标 11 1.1中间件 11 1.1.1中间件的优点 11 1.1.2中间件的分类 12 1.2三种通信技术的比较 13 1.3 WebSphere MQ的原理 15 1.4 WebSphere MQ的重要特点 16 1.4.1统一接口 16 1.4.2处理不依赖时间的限制 16 1.4.3给分布式处理提供的强健的中间件 16 1.5本章小节 17 1.6本章练习 17 第二章Websphere MQ体系结构 18 目标 18 2.1基本概念 18 2.1.1 WebSphere MQ对象(objects) 18 2.1.2 消息 19 2.1.3 队列 20 2.1.4队列管理器 24 2.1.4通道 25 2.1.5进程 29 2.1.6群集 29 2.1.7名称列表 29 2.1.8认证信息对象 30 2.1.9系统缺省对象 30 2.1.10 MQI(message queue interface) 30 2.2体系结构 30 2.2.1 WebSphere MQ和消息排队 31 2.2.2 队列管理器的进程 32 2.3客户机和服务器 33 客户机-服务器环境中的 WebSphere MQ 应用程序 33 2.4触发机制 33 2.4.1触发的概念 33 2.4.2触发类型 34 2.4.3触发的工作原理 35 2.5 队列管理器群集 36 2.5.1 群集的概念 36 2.5.2 群集的优点 37 2.5.3 群集的组件 38 2.5.4 创建群集 38 2.5.5 实现负载均衡 39 2.5.6 群集管理 40 2.6本章小结 41 2.7本章练习 41 第二部分 Websphere MQ系统管理 43 第三章WebSphere MQ系统安装 43 目标 43 3.1 规划安装 43 3.1.1 硬件要求 43 3.1.2 软件要求 44 3.2 安装 WebSphere MQ 46 3.2.1 WebSphere MQ 文档 46 3.2.2 WebSphere MQ安装 47 3.3 验证安装 49 3.3.1安装验证 49 3.3.2测试对象 49 3.4 本章小结 50 3.5本章练习 50 第四章WebSphere MQ 的管理 51 目标 51 4.1 本地和远程管理 51 4.2 使用命令管理 WebSphere MQ 51 4.2.1控制命令 52 4.2.2WebSphere MQ 脚本(MQSC)命令 52 4.2.3PCF 命令 54 4.3 WebSphere MQ 配置 56 4.3.1在 Windows 系统上更改配置信息 56 4.3.2 在 UNIX 系统上更改配置信息 57 4.4 WebSphere MQ 安全性 60 管理 WebSphere MQ 的权限 60 使用WebSphere MQ 对象的权限 61 4.5 WebSphere MQ 事务性支持 61 4.6 WebSphere MQ 死信队列处理程序 62 4.7本章小结 62 4.8本章练习 63 第五章WebSphere MQ 控制命令 64 目标 64 5.1 如何使用控制命令 64 WebSphere MQ 对象的名称 64 5.2 控制命令 65 控制命令集 65 控制命令举例 66 5.3 本章小结 66 5.4本章练习 66 第六章WebSphere MQ 互连通信 68 目标 68 6.1基本概念 68 6.1.1 什么是互连通信 68 6.1.2 分布式队列组件 72 6.1.3 死信队列 75 6.1.4怎样到达远程队列管理器 75 6.2 实现应用程序通信 77 6.2.1发送消息到远程队列管理器 77 6.2.2触发通道 79 6.2.3消息的安全性 80 6.2.4 WebSphere MQ对象配置实例 81 6.3通道的维护 83 6.3.1通道的状态 83 6.3.2通道维护命令 84 6.3.3设置MaxChannels和MaxActiveChannels属性 88 6.4配置侦听程序 88 6.4.1 Windows 平台 88 6.4.2 unix 平台 88 6.5本章小结 89 6.6本章练习 89 第七章 WebSphere MQ 恢复和重新启动 90 目标 90 7.1 WebSphere MQ的数据日志 91 7.1.1日志的概念 91 7.1.2日志控制文件 91 7.1.3日志类型 92 7.1.4计算日志的大小 92 7.2 使用数据日志进行恢复 93 7.2.1从掉电或通信故障中恢复 94 7.2.2恢复受损对象 94 7.3保护 WebSphere MQ 日志文件 96 7.4备份和恢复 WebSphere MQ 96 7.4.1备份 WebSphere MQ 96 7.4.2恢复 WebSphere MQ 96 7.5恢复方案 97 7.5.1磁盘故障 97 7.5.2受损的队列管理器对象 98 7.5.3受损的单个对象 98 7.5.4自动媒体恢复故障 98 7.6使用 dmpmqlog 命令转储日志 98 7.7本章小结 101 7.8本章练习 102 第八章 WebSphere MQ 问题诊断 102 目标 102 8.1错误日志 102 8.1.1日志文件 103 8.1.2忽略WebSphere MQ for Windows的错误代码 104 8.1.3操作信息 104 8.2死信队列 104 8.3配置文件和问题确定 104 8.4跟踪 104 8.4.1WebSphere MQ Windows的跟踪 104 8.4.2WebSphere MQ AIX的跟踪 106 8.5首次故障支持技术(FFST) 109 8.5.1FFST: WebSphere MQ Windows 版 109 8.5.2FFST: WebSphere MQ UNIX 系统版 110 8.6本章小结 112 8.7本章练习 112 第三部分 Websphere MQ 应用开发 113 第九章 设计Websphere MQ应用程序 113 目标 113 9.1介绍应用设计 113 9.1.1 规划设计 113 9.1.2 WebSphere MQ 对象 113 9.1.3 设计消息 114 9.1.4 WebSphere MQ 技术 114 9.1.5应用编程 115 9.1.6 测试应用程序 116 9.2 WebSphere MQ消息 116 9.2.1消息描述符 116 9.2.2消息种类 116 9.2.3消息控制信息和消息数据的格式 117 9.2.4消息优先级 117 9.2.5消息组 118 9.2.6消息持久性 118 9.2.7检索消息 119 9.2.8交付失败的消息 119 9.3本章小结 119 9.4本章练习 119 第十章 用MQI编程 119 目标 119 10.1概述 119 10.2 平台和语言 120 10.3 库和存根模块程序 121 10.4 体系结构模型 122 10.5 用MQI编程 124 10.5.1 基本API概念 125 10.5.2 连接到队列管理器 126 10.5.3 打开WebSphere MQ对象 127 10.5.4 关闭WebSphere MQ对象 130 10.5.5 断开与队列管理器的连接 130 10.5.6 将消息放入队列 131 10.5.7 从队列获取消息 133 10.5.8 从队列浏览消息 135 10.5.9查询对象属性 136 10.5.10设置对象属性 138 10.5.11 MQI中的事务处理 139 10.5.12 MQI中的消息分组 140 10.6本章小结 142 10.7本章练习 142 第十一章 用 C++ API编程 143 目标 143 11.1 概述 143 11.2 平台和语言 144 11.3库 144 11.4体系结构模型 145 11.5用C++ API编程 146 11.5.1连接到队列管理器 147 11.5.2打开WebSphere MQ对象 147 11.5.3 关闭WebSphere MQ对象 148 11.5.4 断开与队列管理器的连接 148 11.5.5 消息放入队列 148 11.5.6从队列获取消息 150 11.5.7浏览队列上的消息 153 11.5.8查询并设置对象属性 153 11.5.9事务处理管理 155 11.5.10消息分组 155 11.6本章小结 157 11.7本章练习 157 第十二章 用Java编程 158 目标 158 12.1 概述 158 12.2 平台 158 12.2.1 获得软件包 158 12.2.2 WebSphere MQ for Java的运行环境 159 12.3 使用WebSphere MQ for Java 161 12.3.1客户机连接模式 161 12.3.2绑定模式 162 12.3.3 类库 162 12.4用WebSphere MQ Java API开展工作 164 12.4.1 设置连接 164 12.4.2 打开队列 165 12.4.3 处理WebSphere MQ消息 166 12.5应用程序开发 167 12.5.1简单的消息发送器应用程序 168 12.5.2简单的消息接收应用程序 170 12.5.3请求/回复 172 12.5.4回复应用程序 175 12.5.5消息分组 177 12.5.6简单的组接收应用程序 180 12.6本章小结 183 12.7本章练习 183 第十三章 用ActiveX编程 183 目标 183 13.1 概述 183 13.2 平台和语言 184 13.3 库 185 13.4 架构模型 185 13.5 用WebSphere MQ automatin classes for ActiveX编程 186 13.5.1 连接到队列管理器 186 13.5.2 打开WebSphere MQ对象 187 13.5.3 基本操作 189 13.5.4 关闭对象 191 13.5.5 关闭连接 192 13.6 事务处理管理 192 13.7 分组 195 13.8 本章小结 195 13.9本章练习 195 第十四章 用AMI编程 195 目标 195 14.1 概述 196 14.2 平台和语言 198 14.3 库和包 199 14.4 体系结构模型 201 14.5 用AMI编程 202 14.5.1 连接到队列管理器 202 14.5.2 打开WebSphere MQ对象 204 14.5.3 基本操作 208 14.5.4 删除会话并关闭连接 212 14.6 AMI和MQI的比较 213 14.7 事务处理管理 213 14.8 分组 215 14.9本章小结 215 14.10本章练习 215 附录一 WebSphere MQ的缺省系统对象 215
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值