1.引言
这篇文章将向您展示在使用JMS异步接收消息期间,使用者执行过程中的错误如何导致消息丢失。 然后,我将解释如何使用本地事务解决此问题。
您还将看到这种解决方案在某些情况下可能导致消息重复(例如,当它将消息保存到数据库中,然后侦听器执行失败时)。 发生这种情况的原因是因为JMS事务独立于其他事务资源(如DB)。 如果您的处理不是幂等的,或者您的应用程序不支持重复消息检测,那么您将不得不使用分布式事务。
分布式事务超出了此职位的范围。 如果您对处理分布式事务感兴趣,可以阅读这篇有趣的文章。
我已经实现了一个再现以下情况的测试应用程序:
- 发送和接收消息:使用者将处理收到的消息,并将其存储到数据库中。
生产者将消息发送到队列:
使用者从队列中检索消息并进行处理:
- 消息处理之前发生错误:使用者检索消息,但是在将消息存储到DB之前执行失败。
- 处理消息后发生错误:使用者检索消息,将其存储到DB,然后执行失败。
- 该应用程序的源代码可以在github上找到。
2.测试应用
测试应用程序执行两个测试类TestNotTransactedMessaging和TestTransactedMessaging 。 这些类都将执行上述三种情况。
让我们看看在没有事务的情况下执行应用程序时的配置。
app-config.xml
应用程序配置。 基本上,它会在指定的软件包内进行检查以自动检测应用Bean:生产者和使用者。 它还配置了将在其中存储处理后的通知的内存数据库。
<context:component-scan base-package="xpadro.spring.jms.producer, xpadro.spring.jms.receiver"/>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
<jdbc:embedded-database id="dataSource">
<jdbc:script location="classp