逻辑与物理排序
队列上的消息可以物理或逻辑顺序(在每个优先级内)显示。
物理顺序是消息到达队列的顺序。 逻辑顺序是满足下列条件时的顺序:当组中的所有消息和段位于其逻辑序列中由属于该组的第一个项的物理位置确定的位置且彼此相邻时。
- 组可以在相近的时间从不同的应用程序到达目标,从而丢失任何明确的物理顺序。
- 即使在单个组内,消息也可能因为组中的某些消息重排或延迟而变得无序。
例如,逻辑顺序可能类似于图 图 1:

- 消息 A(不在组中)
- 组 Y 的逻辑消息 1
- 组 Y 的逻辑消息 2
- 组 Y 的逻辑消息 3(最后一条消息)的段 1
- 组 Y 的逻辑消息 3(最后一条消息)的段 2(最后一个段)
- 组 Z 的逻辑消息 1
- 组 Z 的逻辑消息 2(最后一条消息)
- 消息 B(不在组中)

- 消息 A(不在组中)
- 组 Y 的逻辑消息 1
- 组 Z 的逻辑消息 2
- 组 Y 的逻辑消息 2
- 组 Y 的逻辑消息 3(最后一条消息)的段 1
- 组 Y 的逻辑消息 3(最后一条消息)的段 2(最后一个段)
- 组 Z 的逻辑消息 1
- 消息 B(不在组中)
获取消息时,可指定 MQGMO_LOGICAL_ORDER 以逻辑顺序(而不是物理顺序)来检索消息。
如果发出具有 MQGMO_BROWSE_FIRST 和 MQGMO_LOGICAL_ORDER 的 MQGET 调用,那么具有 MQGMO_BROWSE_NEXT 的后续 MQGET 调用也必须指定 MQGMO_LOGICAL_ORDER。 相反,如果具有 MQGMO_BROWSE_FIRST 的 MQGET 未指定 MQGMO_LOGICAL_ORDER,那么具有 MQGMO_BROWSE_NEXT 的以下 MQGET 也不能指定 MQGMO_LOGICAL_ORDER。
队列管理器为浏览队列上的消息的 MQGET 调用保留的组和段信息与队列管理器为从队列中移除消息的 MQGET 调用保留的组和段信息不同。 指定 MQGMO_BROWSE_FIRST 时,队列管理器会忽略要浏览的组和段信息并扫描队列,如同无当前组和当前逻辑消息一样。
MsgSeqNumber 设置为 1(以查找下一个组的第一条消息),将再次返回已浏览组中的第一条消息。 这可能会即时进行,或在多次 MQGET 调用之后进行(如存在中间组)。- 使用第一个句柄来仅浏览每个组中的第一条消息。
- 使用第二个句柄来仅浏览特定组中的消息。
- 使用 MQMO_* 选项将第二个浏览光标移至第一个浏览光标的位置,然后浏览组中的消息。
- 请勿在组末尾以外使用 MQGMO_BROWSE_NEXT 浏览。
对于大多数应用程序,浏览时您将可能选择逻辑排序或物理排序。 但是,如果要在这些方式之间切换,请记住在使用 MQGMO_LOGICAL_ORDER 第一次发出浏览时,将确定您在逻辑序列中的位置。
如果组内的第一个项此时不存在,那么不会将您所在的组视为逻辑序列的一部分。
一旦浏览光标在组内,便可在同一组内继续操作,即使移除第一条消息也是如此。 但是一开始,您绝不能使用 MQGMO_LOGICAL_ORDER 移至第一个项不存在的组中。
- MQPMO_LOGICAL_ORDER
- MQPMO 选项告知队列管理器应用程序如何将消息放入逻辑消息的组和段中。 只能对 MQPUT 调用指定此选项;它对于 MQPUT1 调用是无效的。如果指定 MQPMO_LOGICAL_ORDER,那么指示应用程序使用连续的 MQPUT 调用来执行以下操作:
- 按段偏移量的递增顺序(从 0 开始,无间隔)放置每条逻辑消息中的段。
- 先放置一条逻辑消息中的所有段,然后再放置下一条逻辑消息中的段。
- 按消息序号的递增顺序(从 1 开始,无间隔)放置每个消息组中的逻辑消息。 IBM MQ 会自动递增消息序号。
- 先放置一个消息组中的所有逻辑消息,然后再放置下一个消息组中的逻辑消息。
由于应用程序已告知队列管理器它如何将消息放在逻辑消息的组和段中,因此应用程序无需保留和更新有关每个 MQPUT 调用的组和段信息,因为队列管理器会保留和更新此信息。 特别地,这意味着应用程序无需在 MQMD 中设置
GroupId、MsgSeqNumber和Offset字段,因为队列管理器将这些字段设置为相应的值。 应用程序必须仅在 MQMD 中设置MsgFlags字段,以指示消息何时属于组或成为逻辑消息段,并指示组中的最后一条消息或逻辑消息的最后一个段。启动消息组或逻辑消息后,后续的 MQPUT 调用必须在 MQMD 中的
MsgFlags中指定相应的 MQMF_* 标志。 如果应用程序尝试在存在未结束的消息组时放入不在组中的消息,或在存在未结束的逻辑消息时放入非段消息,那么调用将失败,并根据情况返回原因码 MQRC_INCOMPLETE_GROUP 或 MQRC_INCOMPLETE_MSG。 但是,队列管理器将保留有关当前消息组或当前逻辑消息的信息,应用程序可通过发送消息(可能无任何应用程序消息数据),根据情况指定 MQMF_LAST_MSG_IN_GROUP 或 MQMF_LAST_SEGMENT,然后重新发出 MQPUT 调用来放入不在组中或非段的消息来进行终止。图 2 显示了有效的选项和标志的组合,以及队列管理器在每种情况下使用的GroupId,MsgSeqNumber和Offset字段的值。 此表中未显示的选项和标志组合无效。 此表中的列具有以下含义;“是”或“否”:- LOG ORD
- 是否在调用上指定 MQPMO_LOGICAL_ORDER 选项。
- MIG
- 是否在调用上指定 MQMF_MSG_IN_GROUP 或 MQMF_LAST_MSG_IN_GROUP 选项。
- SEG
- 是否在调用上指定 MQMF_SEGMENT 或 MQMF_LAST_SEGMENT 选项。
- SEG OK
- 是否在调用上指定 MQMF_SEGMENTATION_ALLOWED 选项。
- Cur grp
- 是否在调用前存在当前消息组。
- Cur log msg
- 是否在调用前存在当前逻辑消息。
- 其他列
- 显示队列管理器使用的值。 上一项表示用于队列句柄的上一条消息中的字段的值。
表 1. 与逻辑消息的组和段中的消息相关的 MQPUT 选项 指定的选项 指定的选项 指定的选项 指定的选项 调用前的组和 log-msg 状态 调用前的组和 log-msg 状态 队列管理器使用的值 队列管理器使用的值 队列管理器使用的值 LOG ORD MIG SEG SEG OK Cur grp Cur log msg GroupId MsgSeqNumber Offset Yes 否 否 否 否 否 MQGI_NONE 1 0 Yes 否 否 Yes 否 否 新组标识 1 0 Yes 否 Yes 任一 否 否 新组标识 1 0 Yes 否 Yes 任一 否 Yes 前一个组标识 1 前一个偏移量 + 前一个段长 Yes Yes 任一 任一 否 否 新组标识 1 0 Yes Yes 任一 任一 Yes 否 前一个组标识 前一个序列号 + 1 0 Yes Yes Yes 任一 Yes Yes 前一个组标识 前一个序列号 前一个偏移量 + 前一个段长 否 否 否 否 任一 任一 MQGI_NONE 1 0 否 否 否 Yes 任一 任一 新组标识(如果指定 MQGI_NONE),否则为字段中的值 1 0 否 否 Yes 任一 任一 任一 新组标识(如果指定 MQGI_NONE),否则为字段中的值 1 字段中的值 否 Yes 否 任一 任一 任一 新组标识(如果指定 MQGI_NONE),否则为字段中的值 字段中的值 0 否 Yes Yes 任一 任一 任一 新组标识(如果指定 MQGI_NONE),否则为字段中的值 字段中的值 字段中的值 注:- MQPMO_LOGICAL_ORDER 在 MQPUT1 调用上无效。
- 对于
MsgId字段,如果已指定 MQPMO_NEW_MSG_ID 或 MQMI_NONE,那么队列管理器将生成新的消息标识,如果未指定,那么使用该字段中的值。 - 对于
CorrelId字段,如果已指定 MQPMO_NEW_CORREL_ID,那么队列管理器将生成新的相关标识,如果未指定,那么使用该字段中的值。
指定 MQPMO_LOGICAL_ORDER 时,队列管理器要求使用 MQMD 中的
Persistence字段中的相同值,放入逻辑消息中的组和段中的所有消息,也就是说,所有项都必须是持久性的,或必须是非持久性的。 如果不满足此条件,那么 MQPUT 调用将失败,显示原因码 MQRC_INCONSISTENT_PERSISTENCE。MQPMO_LOGICAL_ORDER 选项会影响工作单元,如下所述:- 如果将组或逻辑消息中的第一条物理消息放入一个工作单元内,那么该组或逻辑消息中的所有其他物理消息都必须放入一个工作单元内(如果使用相同的队列句柄)。 但是,无需将它们放入同一工作单元内,这表示允许包含多条物理消息的消息组或逻辑消息拆分到队列句柄的两个或更多连续工作单元中。
- 如果未将组或逻辑消息中的第一条物理消息放入一个工作单元内,那么该组或逻辑消息中的所有其他物理消息都不能放入一个工作单元内(如果使用相同的队列句柄)。
指定 MQPMO_LOGICAL_ORDER 时,MQPUT 调用上提供的 MQMD 不得低于 MQMD_VERSION_2。 如果不满足此条件,那么调用将失败,显示原因码 MQRC_WRONG_MD_VERSION。
如未指定 MQPMO_LOGICAL_ORDER,那么可以任何顺序放入逻辑消息的组和段中的消息,并且无需放入完整的消息组或完整的逻辑消息。 应用程序应确保
GroupId、MsgSeqNumber、Offset和MsgFlags字段具有相应的值。系统故障发生后,请使用此方法在此期间重新启动消息组或逻辑消息。 系统重新启动时,应用程序可将
GroupId、MsgSeqNumber、Offset、MsgFlags和Persistence字段设置为相应的值,然后根据需要发出设置了 MQPMO_SYNCPOINT 或 MQPMO_NO_SYNCPOINT 的 MQPUT 调用,但不指定 MQPMO_LOGICAL_ORDER。 如果成功进行此调用,队列管理器将保留组和段信息,并且使用此队列句柄的后续 MQPUT 调用可正常指定 MQPMO_LOGICAL_ORDER。队列管理器为 MQPUT 调用保留的组和段信息与其为 MQGET 调用保留的组和段信息不同。
对于任意给定的队列句柄,应用程序可混合指定了 MQPMO_LOGICAL_ORDER 的 MQPUT 调用和未指定 MQPMO_LOGICAL_ORDER 的 MQPUT 调用,但请注意以下几点:- 如果未指定 MQPMO_LOGICAL_ORDER,那么每个成功的 MQPUT 调用都会使队列管理器将队列句柄的组和段信息设置为应用程序指定的值,替换队列管理器为队列句柄保留的现有组和段信息。
- 如果未指定 MQPMO_LOGICAL_ORDER,那么在存在当前消息组或逻辑消息的情况下,调用不会失败;可能会成功调用,显示完成代码 MQCC_WARNING。 表 2 显示了可能出现的各种情况。 在这些情况下,如果完成代码不是 MQCC_OK,那么原因码为以下项之一(视情况而定):
- MQRC_INCOMPLETE_GROUP
- MQRC_INCOMPLETE_MSG
- MQRC_INCONSISTENT_PERSISTENCE
- MQRC_INCONSISTENT_UOW
注: 队列管理器不会检查 MQPUT1 调用的组和段信息。
表 2. MQPUT 或 MQCLOSE 调用与组和段信息不一致时的结果 当前调用是 前一调用是 MQPUT,使用 MQPMO_LOGICAL_ORDER 前一调用是 MQPUT,不使用 MQPMO_LOGICAL_ORDER MQPUT,使用 MQPMO_LOGICAL_ORDER MQCC_FAILED MQCC_FAILED MQPUT,不使用 MQPMO_LOGICAL_ORDER MQCC_WARNING MQCC_OK MQCLOSE,使用未结束的组或逻辑消息 MQCC_WARNING MQCC_OK 对于以逻辑顺序放入消息和段的应用程序,指定 MQPMO_LOGICAL_ORDER,因为它是可使用的最简单的选项。 该选项可使应用程序无需管理组和段信息,因为队列管理器会管理此信息。 但是,特殊的应用程序可能需要较之 MQPMO_LOGICAL_ORDER 选项提供的功能更大的控制能力,这可通过不指定该选项来实现;如果不指定,那么必须确保正确设置 MQMD 中的
GroupId、MsgSeqNumber、Offset和MsgFlags字段,然后再进行每个 MQPUT 或 MQPUT1 调用。例如,要转发所接收的物理消息(而不考虑这些消息是否在逻辑消息的组或段中)的应用程序,不得指定 MQPMO_LOGICAL_ORDER,原因有二:- 如果按顺序检索和放入消息,那么指定 MQPMO_LOGICAL_ORDER 会将新组标识分配给消息,这会使消息发起方很难或无法关联由消息组生成的任何回复或报告消息。
- 在发送和接收队列管理器间具有多条路径的复杂网络中,物理消息到达时可能杂乱无序。 通过在 MQGET 调用上不指定 MQPMO_LOGICAL_ORDER 和 MQGMO_LOGICAL_ORDER,转发应用程序可在每条物理消息到达时立即对其进行检索和转发,而无需等待下一条采用逻辑顺序的消息到达。
为逻辑消息的组或段中的消息生成报告消息的应用程序也不得在放入报告消息时指定 MQPMO_LOGICAL_ORDER。
可以使用其他 MQPMO_* 选项中的任一选项来指定 MQPMO_LOGICAL_ORDER。
将逻辑排序的组放入集群队列 (MQOO_BIND_ON_GROUP)
- MQPUT 调用必须指定 MQPMO_LOGICAL_ORDER
- MQOPEN 调用必须指定以下两个选项之一:
- MQOO_BIND_ON_GROUP
- MQOO_BIND_AS_Q_DEF,队列定义必须指定 DEFBIND(GROUP)
随后会在消息的组间驱动工作负载均衡,无需队列的 MQCLOSE 和 MQOPEN。 组间意味着在 MQMD(v2) 或 MQMDE 中设置 MQMF_MSG_IN_GROUP,没有正在进行的未完成组。 当组正在进行中时,将复用解析的队列管理器和对象句柄中的队列名称。
如果先前的消息是 MQPMO_LOGICAL_ORDER 且/或设置了 MQMF_MSG_IN_GROUP,但当前消息不是组的一部分,那么 PUT 调用将失败并显示 MQRC_INCOMPLETE_GROUP。
如果单个 MQPUT 未指定 MQPMO_LOGICAL_ORDER,并且没有处于活动状态的当前组,那么将对此消息驱动工作负载均衡(如同已对 MQOPEN 调用指定了 MQOO_BIND_NOT_FIXED 一样)。
不会对使用 MQOO_BIND_ON_GROUP 绑定到目标的消息进行重新分配。 有关重新分配的更多信息,请参阅 信息组。