我确实有以下(多线程)流程:
我的问题源于我的应用程序可能在第2步和第3步之间意外死亡,然后应用程序在重新启动时会产生重复的消息。
有没有办法将邮件标记为“脏”'或者'处理'在队列中(在阅读它的同时或之后),即使应用程序重新启动,标记仍然存在?
我曾尝试使用MQ提供的标记,但它们无法在重新启动后继续存在。另一种可能性是将消息移至“处理”状态。队列,成功时将其删除或在失败时将其移回源队列,但这需要第二个队列,而不再是简单的代码。
粗略代码示例:
MQGetMessageOptions gmo = new MQGetMessageOptions();
gmo.options = MQConstants.MQGMO_BROWSE_FIRST | MQConstants.MQGMO_LOCK;
MQMessage message = new MQMessage();
message.correlationId = MQC.MQCI_NONE;
message.messageId = MQC.MQMI_NONE;
queue.get(message, gmo);
boolean success = processMessage(message);
// Application gets killed here after successful message processing.
// Produces duplicate after restart.
if (success) {
MQGetMessageOptions gmo2 = new MQGetMessageOptions();
gmo2.options = MQConstants.MQGMO_MSG_UNDER_CURSOR;
queue.get(new MQMessage(), gmo2);
}
基本上,我想实现这个目标:
如果应用程序在成功完成第三步'处理消息后立即死亡,则该消息将被标记为"处理"并且不会再次处理(因为它可能已经存在)。
注意:我不希望此过程对消息处理有任何了解(除了成功之外)。
答案 0 :(得分:0)
您是否尝试过SYNCPOINT?在这种情况下,提交或回退类型的操作可能有所帮助。
答案 1 :(得分:0)
你的解决方案是一个可怕的设计。如果要更新数据库,那么为什么不使用2阶段提交(即XA事务)?
让MQAdmin设置队列管理器以使用您正在使用的特定数据库的资源管理器,然后就像这样简单:
因此,事务,MQGET和数据库更新中的所有内容将一起提交或一起退出。
如果您的应用程序崩溃,那么资源管理器将自动退出事务中的所有内容。
假设您不想使用2阶段提交,或者您没有更新数据库(更新文件),那么您可以使用单阶段UOW(工作单元)。
关于MQ的事情:
如果应用程序发出 MQDISC或正常结束 ,使用当前未提交的操作,则会执行 隐含的MQCMIT :IBM MQ,即在SYNCPOINT下完成的所有操作都已提交。
如果应用程序 异常结束 ,使用当前未提交的操作,则会执行 隐含的MQBACK 通过IBM MQ,即回滚在SYNCPOINT下完成的所有操作。