在跨线程共享连接的事务场景下,使用IBM MQ基类实现连接池的推荐做法是什么?
我正在使用IBM MQ Java基础类(com.ibm.mq.MQQueueManager)并需要实现连接池。由于无法切换到JMS API,因此解决方案必须使用IBM MQ Java基础类。
我的理解是:
MQQueueManager表示一个物理的MQ客户端连接。- 在使用事务(
commit()/backout())时,单个MQQueueManager不能跨不相关线程安全地并发共享,因为事务范围与MQ连接相关联。 - 如果多个线程共享同一个
MQQueueManager,一个线程的commit()或backout()可能会影响到另一个线程的工作单元。
我尝试了几种选项,但似乎每种都存在缺点:
- 共享MQQueueManager
MQQueueManager qmgr = new MQQueueManager(...);
所有线程使用同一个实例。
问题:
- 事务边界被共享。
-
commit()和backout()在跨线程时变得不安全。 -
线程本地化MQQueueManager
MQQueueManager qmgr = new MQQueueManager(...);
每个线程创建或拥有自己的队列管理器连接。
问题:
- 这并不真正构成连接池。
- 大量线程可能导致大量MQ连接。
-
很难强制执行诸如“每个应用最多10个 MQ连接”等限制。
-
MQSimpleConnectionManager / MQSimpleQueueManager
我找到了对 MQSimpleConnectionManager(或类似的连接管理实现)的引用,但据我理解:
MQEnvironment.setDefaultConnectionManager(...)
或
MQEnvironment.setDefaultQueueManager(...)
引入了一个JVM级别的配置。
问题:
- 我可能在同一个JVM中拥有多个逻辑MQ客户端。
- 我希望对目标MQ服务器 / 队列管理器设定连接限制,而不是一个单一JVM级别的限制。
我想实现类似这样的方案:
host1:1414:QM1 -> max 5 connections
host2:1414:QM2 -> max 10 connections
具备:
- 连接重用
- 事务隔离
- 不对同一个可事务连接进行并发共享
- 仅使用IBM MQ Base Classes(不使用JMS)
问题:
- 当使用
MQQueueManager时,IBM推荐的连接池实现方式是什么? MQSimpleConnectionManager仍然是此用例的首选解决方案吗?- 人们通常如何实现按队列管理器的池限制,而不是JVM级别的限制?
- 是否存在IBM MQ支持的机制,在实现连接重用的同时保持线程之间的事务隔离?
- 如果推荐的方法是应用程序管理的
MQQueueManager实例池,关于池大小、事务处理或连接验证,IBM MQ是否有最佳实践?
解决方案
为什么不使用两个不同的MQSimpleConnectionManager,并设置不同的最大连接数?我尝试了这个,似乎可行。通过跟踪,我看到每个队列管理器只创建一个连接,下一次连接尝试时会重复使用同一个连接。
private MQSimpleConnectionManager setupPool(int poolSize) throws MQException {
MQSimpleConnectionManager myConnMan = new MQSimpleConnectionManager();
myConnMan.setActive(MQSimpleConnectionManager.MODE_ACTIVE);
myConnMan.setMaxConnections(poolSize);
return myConnMan;
}
private void runTest() {
try {
myConnManQM1 = setupPool(5);
myConnManQM2 = setupPool(15);
for (int i = 0; i < 10; i++) {
putMessageToQM1(i, myConnManQM1);
putMessageToQMVerifyAMS(i, myConnManQM2);
}
destroyPool(myConnManQM1);
destroyPool(myConnManQM2);
} catch (MQException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void putMessageToQM1(int count, MQSimpleConnectionManager myConnMan) {
try {
Hashtable properties = new Hashtable();
properties.put(MQConstants.USER_ID_PROPERTY, "MyUserId");
properties.put(MQConstants.PASSWORD_PROPERTY, "MyLongPassw0rd");
MQQueueManager qmgr=new MQQueueManager("QM1", properties, myConnMan);
MQQueue queue = qmgr.accessQueue("TEST.QUEUE", MQConstants.MQOO_OUTPUT | MQConstants.MQOO_FAIL_IF_QUIESCING);
MQMessage msg = new MQMessage();
msg.writeUTF("Hello - testing MQSimpleConnectionManager " + count);
queue.put(msg);
queue.close();
qmgr.disconnect();
} catch(MQException ex) {
ex.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void putMessageToQMVerifyAMS(int count, MQSimpleConnectionManager myConnMan) {
try {
Hashtable properties = new Hashtable();
properties.put(MQConstants.USER_ID_PROPERTY, "MyUserId");
properties.put(MQConstants.PASSWORD_PROPERTY, "MyLongPassw0rd");
MQQueueManager qmgr=new MQQueueManager("QM2", properties, myConnMan);
MQQueue queue = qmgr.accessQueue("TEST.QUEUE", MQConstants.MQOO_OUTPUT | MQConstants.MQOO_FAIL_IF_QUIESCING);
MQMessage msg = new MQMessage();
msg.writeUTF("Hello - testing MQSimpleConnectionManager " + count);
queue.put(msg);
queue.close();
qmgr.disconnect();
} catch(MQException | IOException ex) {
ex.printStackTrace();
}
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。