ActiveMQ的消息持久化---JDBC的實現方式

對於queue的方式做到持久化很簡單。每個消息只有一個消費者,只要將消息存入數據庫,然後消費者取走信息即可,在這裏我們討論的是topic的持久化方式。

1.在這裏我用的是oracle數據庫,先將oracle的驅動包放入lib文件夾下,再配置activemq.xml文件中的配置信息

將原來的默認持久化方式改爲使用jdbc的方式:

		<!--配置JDBC適配器:-->
		<persistenceAdapter>
			<jdbcPersistenceAdapter dataDirectory="${activemq.base}/data" dataSource="#oracle-ds" useDatabaseLock="false"/>
		</persistenceAdapter>
配置oracle-ds的bean,注意須將bean配置在broker節點之外

	<bean id="oracle-ds" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
		<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/>
		<property name="username" value="scott"/>
		<property name="password" value="tiger"/>
		<property name="maxTotal" value="200"/>
		<property name="poolPreparedStatements" value="true"/>
	</bean>


2.編寫生產者與消費者類

生產者

package com.yc.mytest;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;

public class MyProducer {
	private static final String URL=ActiveMQConnection.DEFAULT_BROKER_URL; //默認的連接地址
	private static String TOPIC_NAME="MyTopicTest"; //topic名字

	public static void main(String[] args) {
		ConnectionFactory factory; //連接工廠
		Connection conn = null; //連接
		Session session; //會話
		Destination dest; //消息的目的地
		MessageProducer producer; //消息生產者

		try {
			//初始化連接工廠
			factory=new ActiveMQConnectionFactory(URL); 

			//獲取連接
			conn=factory.createConnection(); 

			//開始連接
			conn.start();

			//創建Session,此方法第一個參數表示會話是否在事務中執行,第二個參數設定會話的應答模式
			session=conn.createSession(false, Session.AUTO_ACKNOWLEDGE);

			//創建topic,producer和consumer將根據TOPIC_NAME來發送/接收對應的消息 
			dest=session.createTopic(TOPIC_NAME); 

			//創建生產者
			producer=session.createProducer(dest);

			//設置持久化
			producer.setDeliveryMode(DeliveryMode.PERSISTENT);

			//發送消息
			sendMessage(session, producer);
		} catch (Exception e) {
			System.out.println("出錯啦!!!");
			e.printStackTrace();
		} finally{
			if(conn!=null){
				try {
					//關閉連接
					conn.close();
				} catch (JMSException e) {
					e.printStackTrace();
				}
			}
		}
	}

	private static void sendMessage(Session session,MessageProducer producer) throws JMSException{
		//初始化一個mq消息
		TextMessage message = session.createTextMessage() ;//= session.createTextMessage("你好 ActiveMq " + i);
		//填寫消息內容
		message.setText("你好 ActiveMq");
		//發送消息
		producer.send(message);
		System.out.println("消息發送成功!!!");
	}
}



消費者

package com.yc.mytest;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;

public class MyConsumer implements MessageListener {
	private static final String URL=ActiveMQConnection.DEFAULT_BROKER_URL; //默認的連接地址
	private static String TOPIC_NAME="MyTopicTest"; //topic名字

	public static void main(String[] args) {
		ConnectionFactory factory; //連接工廠
		Connection conn = null; //連接
		Session session; //會話
		Destination dest; //消息的目的地
		MessageConsumer consumer; //消費者
		
		try {
			//初始化連接工廠
			factory=new ActiveMQConnectionFactory(URL); 

			//獲取連接
			conn=factory.createConnection(); 
			
			conn.setClientID("C1");
			
			//開始連接
			conn.start(); 
			
			//創建Session,此方法第一個參數表示會話是否在事務中執行,第二個參數設定會話的應答模式
			session=conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
			
			//創建topic,producer和consumer將根據TOPIC_NAME來發送/接收對應的消息 
			dest=session.createTopic(TOPIC_NAME); 
			
			//創建消費者
			//consumer=session.createConsumer(dest);
			
			//創建消費者(持久化)
			consumer = session.createDurableSubscriber((Topic) dest, TOPIC_NAME);
			
			//初始化MessageListener
			MyConsumer me=new MyConsumer();
			
			//給消費者設定監聽對象
			consumer.setMessageListener(me);
		} catch (Exception e) {
			System.out.println("出錯啦!!!");
			e.printStackTrace();
		}
	}
	
	public void onMessage(Message message) {
		TextMessage txtMessage = (TextMessage)message;
		String text;
		try {
			text=txtMessage.getText();
			//txtMessage.acknowledge(); //通知服務器
			System.out.println("收到消息:"+text);
		} catch (JMSException e) {
			System.out.println("出錯啦!!!");
			e.printStackTrace();
		}
	}
}
在這裏我們可以編寫兩個消費者模擬羣發的測試,須要對conn.setClient()設置不同的id。筆者使用了C1與C2,由於代碼相同,我就不貼C2的代碼了。


3.分析與測試

在使用jdbc的方式實現持久化的時候,activemq會在數據庫創建三張表,ACTIVEMQ_MSGS,ACTIVEMQ_ACKS和ACTIVEMQ_LOCK。第二張表外鍵關聯到第一張表,共同存儲消息,第三張表用於鎖定保證只有一個broker實例可以訪問數據庫。

測試:

1.先啓動MyConsumer類,讓MyConsumer在自己的主題上進行訂閱
2.停止MyConsumer類,再啓動MyProducer類
3.待MyProducer類運行完成後,再啓動MyConsumer類
4.發現數據庫中存在信息,相應主題的信息被訂閱,證明持久化成功。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章