轉自:https://blog.csdn.net/lsm135/article/details/74945116
1. 啓用消息事務
<property name="sessionTransacted" value="true"/>
2. 當消息在消費的時候,如果用戶程序拋出Exception,則消息會回滾重傳(mq裏面的未消費消息數目不變),
spring 的activemq默認最多重傳6次, 超過6次,即使拋出了異常,這個消費仍然被消費不可回滾。
jms.redeliveryPolicy.maximumRedeliveries=6(默認)
我們可以設置brokerURL裏面的jms.redeliveryPolicy.maximumRedeliveries=-1
-1表示可以無限次重傳,0表示不重傳。
注意中間要用 html轉移符 & (就是url查詢字符串裏的&字符)
3.消息隊列回滾的觸發--程序本身運行異常,比如數據庫操作異常,如果自己用程序去檢查數據庫更新條數,如果小於1,程序可以人爲編寫代碼,人爲
拋出一個RuntimeException. 這兩種情況都能觸發消息的rollback
如在onMesssage()裏,或者內部嵌套的方法裏
throw new RuntimeException("Update DB failed.");
最終配置文件如下
appContext.xml
-
<?xml version="1.0" encoding="UTF-8"?>
-
<beans xmlns="http://www.springframework.org/schema/beans"
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
-
xsi:schemaLocation="
-
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
-
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
-
<import resource="mybatisContext.xml" />
-
<import resource="shardingContext.xml" />
-
<!-- 配置JMS連接工廠 -->
-
<!-- 測試環境 -->
-
<bean id="jmsFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory">
-
<property name="brokerURL"
-
value="failover:(tcp://10.0.0.9:61616)?randomize=false&timeout=3000&initialReconnectDelay=100&jms.useAsyncSend=true&jms.redeliveryPolicy.maximumRedeliveries=-1" />
-
</bean>
-
<!-- 配置JMS模版 -->
-
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
-
<property name="connectionFactory">
-
<!-- lets wrap in a pool to avoid creating a connection per send -->
-
<bean class="org.springframework.jms.connection.SingleConnectionFactory">
-
<property name="targetConnectionFactory">
-
<ref local="jmsFactory" />
-
</property>
-
</bean>
-
</property>
-
</bean>
-
<!-- MQ監聽者 -->
-
<bean id="smsSendForMQListener"
-
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
-
<property name="connectionFactory">
-
<ref bean="jmsFactory" />
-
</property>
-
<property name="destinationName">
-
<value>DistributePics</value>
-
</property>
-
<property name="messageListener">
-
<ref bean="saveListener" />
-
</property>
-
<!-- mq事務控制,如果拋異常了就回滾消息 -->
-
<property name="sessionTransacted" value="true"/>
-
</bean>
-
<!-- Spring MVC -->
-
<context:component-scan base-package="com.x.service"></context:component-scan>
-
<context:component-scan base-package="com.x.controller.**"></context:component-scan>
-
<context:component-scan base-package="com.x.listener"></context:component-scan>
-
<context:component-scan base-package="com.x.spring"></context:component-scan>
-
</beans>
java程序如下:
-
package com.x.imgapp.listener;
-
import java.util.concurrent.Future;
-
import javax.jms.JMSException;
-
import javax.jms.Message;
-
import javax.jms.MessageListener;
-
import javax.jms.ObjectMessage;
-
import javax.jms.BytesMessage;
-
import org.springframework.stereotype.Component;
-
import com.x.imgapp.common.model.MsgBean;
-
import com.x.imgapp.concurrent.AppExecutor;
-
import com.x.imgapp.concurrent.MoveThread;
-
import org.apache.activemq.command.ActiveMQBytesMessage;
-
import org.apache.activemq.util.ByteSequence;
-
import org.slf4j.Logger;
-
import org.slf4j.LoggerFactory;
-
/**
-
*
-
* @author frank.liu
-
*
-
*/
-
@Component("saveListener")
-
public class SaveDBListener implements MessageListener {
-
private static final Logger logger = LoggerFactory.getLogger(SaveDBListener.class);
-
private static Long receiveCount = 0L;
-
@Override
-
public void onMessage(Message message) {
-
logger.info("Step into onMessage()------------------------------->");
-
ActiveMQBytesMessage msg = (ActiveMQBytesMessage) message;
-
ByteSequence sequence = msg.getContent();
-
String msgStr = new String(sequence.data);
-
//
-
// Future<Integer> future = AppExecutor.getExecutor().submit(new MoveThread(msgStr));
-
logger.info("receiveCount:{}", ++receiveCount);
-
throw new RuntimeException("Update DB failed.");
-
}
-
}