在跨线程共享连接的事务场景下,使用IBM MQ基类实现连接池的推荐做法是什么?

编程语言 2026-07-08

我正在使用IBM MQ Java基础类(com.ibm.mq.MQQueueManager)并需要实现连接池。由于无法切换到JMS API,因此解决方案必须使用IBM MQ Java基础类。

我的理解是:

  • MQQueueManager 表示一个物理的MQ客户端连接。
  • 在使用事务(commit() / backout())时,单个 MQQueueManager 不能跨不相关线程安全地并发共享,因为事务范围与MQ连接相关联。
  • 如果多个线程共享同一个 MQQueueManager,一个线程的 commit()backout() 可能会影响到另一个线程的工作单元。

我尝试了几种选项,但似乎每种都存在缺点:

  1. 共享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)

问题:

  1. 当使用 MQQueueManager 时,IBM推荐的连接池实现方式是什么?
  2. MQSimpleConnectionManager 仍然是此用例的首选解决方案吗?
  3. 人们通常如何实现按队列管理器的池限制,而不是JVM级别的限制?
  4. 是否存在IBM MQ支持的机制,在实现连接重用的同时保持线程之间的事务隔离?
  5. 如果推荐的方法是应用程序管理的 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导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章