begin
dbms_aqadm.create_queue_table(
queue_table => 'demo_queue_table',
queue_payload_type => 'demo_queue_payload_type',
multiple_consumers => true
);
end;
4.我们要创建一个队列并且启动它 ,PS : 后续的章节我将写到如何删除和停止队列 , 和创建的过程中相关的对象的查看
--创建队列并启动队列:
DECLARE
subscriber sys.aq$_agent;
BEGIN
-- 创建队列
dbms_aqadm.create_queue (
queue_name => 'demo_queue',
queue_table => 'demo_queue_table'
);
--启动队列
dbms_aqadm.start_queue(
queue_name => 'demo_queue'
);
--设置订阅人
subscriber := sys.aq$_agent('recuser1', NULL, NULL);
DBMS_AQADM.ADD_SUBSCRIBER(queue_name => 'demo_queue',
subscriber => subscriber);
END;
5.我们要尝试使用aq来入队一条消息
-- 入列操作是一个基本的事务操作(表数据的插入),因此我们需要Commit
declare
r_enqueue_options DBMS_AQ.ENQUEUE_OPTIONS_T;
r_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T;
v_message_handle RAW(16);
o_payload demo_queue_payload_type;
begin
o_payload := demo_queue_payload_type('Hello JMS ?');
dbms_aq.enqueue(
queue_name => 'demo_queue',
enqueue_options => r_enqueue_options,
message_properties => r_message_properties,
payload => o_payload,
msgid => v_message_handle
);
commit;
end;
6.我们如何出队一条消息
declare
r_dequeue_options DBMS_AQ.DEQUEUE_OPTIONS_T;
r_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T;
v_message_handle RAW(16);
o_payload demo_queue_payload_type;
begin
DBMS_AQ.DEQUEUE(
queue_name => 'demo_queue',
dequeue_options => r_dequeue_options,
message_properties => r_message_properties,
payload => o_payload,
msgid => v_message_handle
);
DBMS_OUTPUT.PUT_LINE(
'***** Browse message is [' || o_payload.message || ']****'
);
end;
出队操作我没有尝试 , 很遗憾的告诉大家 , 此段代码来自于 scorpio3k Click here
我们如何在JMS中接收AQ入队的消息
首先前提是我文章开始所提到的jar 你安装在了你相关的应用程序上面
直接上代码 , 不懂的同学可以参阅其他博文或者查阅Oracle JMS 的相关文档
package *********;
import java.sql.SQLException;
import java.util.Properties;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Session;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import oracle.jms.AQjmsAdtMessage;
import oracle.jms.AQjmsConsumer;
import oracle.jms.AQjmsDestination;
import oracle.jms.AQjmsFactory;
import oracle.jms.AQjmsSession;
public class Main {
@SuppressWarnings("unused")
private TopicConnection getTopicConnection(String jdbcUrl, String username, String password) throws JMSException {
Properties info = new Properties();
info.put(username, password);
TopicConnectionFactory topicConnectionFactory = AQjmsFactory.getTopicConnectionFactory(jdbcUrl, info);
return topicConnectionFactory.createTopicConnection(username, password);
}
public static void main(String[] args) throws InterruptedException {
JmsConfig config = new JmsConfig();
try {
TopicConnection conn = new Main().getTopicConnection(config.jdbcUrl, config.username, config.password);
AQjmsSession session = (AQjmsSession) conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
AQjmsDestination topic = (AQjmsDestination) session.getTopic(config.username, config.queueName);
AQjmsConsumer subscriber = (AQjmsConsumer) session.createDurableSubscriber(topic, "recuser1",
QUEUE_MESSAGE_TYPE_1.getORADataFactory());//注意订阅人
topic.start(session, false, true);
//Message msg = subscriber.receive(10000);
subscriber.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
try {
AQjmsAdtMessage adtMessage = (AQjmsAdtMessage) message;
QUEUE_MESSAGE_TYPE_1 payload = (QUEUE_MESSAGE_TYPE_1) adtMessage.getAdtPayload();
System.out.println("队列消息 : " + payload.getMessage());
} catch (JMSException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
});
Thread.sleep(1000000);
} catch (JMSException e) {
e.printStackTrace();
}
}
}
代码很渣 , 大神别喷我 , 下面是关于数据库配置的一些描述类
package **********;
public class JmsConfig {
public String username = "devuser";
public String password = "******";
public String jdbcUrl = "jdbc:oracle:thin:@127.0.0.1:1521:XE";
public String queueName = "demo_queue";
}
在下面是关于消息负荷的Oracle Type 到JAVA 类型的转换
package *****************;
import java.sql.Connection;
import java.sql.SQLException;
import oracle.jdbc.OracleTypes;
import oracle.jpub.runtime.MutableStruct;
import oracle.sql.Datum;
import oracle.sql.ORAData;
import oracle.sql.ORADataFactory;
import oracle.sql.STRUCT;
public class QUEUE_MESSAGE_TYPE_1 implements ORAData, ORADataFactory {
public static final String _SQL_NAME = "devuser.DEMO_QUEUE_PAYLOAD_TYPE";
public static final int _SQL_TYPECODE = OracleTypes.STRUCT;
protected MutableStruct _struct;
protected static int[] _sqlType = {12};
protected static ORADataFactory[] _factory = new ORADataFactory[3];
protected static final QUEUE_MESSAGE_TYPE_1 _QUEUE_MESSAGE_TYPE_1Factory = new QUEUE_MESSAGE_TYPE_1();
public static ORADataFactory getORADataFactory() {
return _QUEUE_MESSAGE_TYPE_1Factory;
}
/* constructors */
protected void _init_struct(boolean init) {
if (init)
_struct = new MutableStruct(new Object[3], _sqlType, _factory);
}
public QUEUE_MESSAGE_TYPE_1() {
_init_struct(true);
}
public QUEUE_MESSAGE_TYPE_1(String message) throws SQLException {
_init_struct(true);
setMessage(message);
}
/* ORAData interface */
public Datum toDatum(Connection c) throws SQLException {
return _struct.toDatum(c, _SQL_NAME);
}
/* ORADataFactory interface */
public ORAData create(Datum d, int sqlType) throws SQLException {
return create(null, d, sqlType);
}
protected ORAData create(QUEUE_MESSAGE_TYPE_1 o, Datum d, int sqlType) throws SQLException {
if (d == null)
return null;
if (o == null)
o = new QUEUE_MESSAGE_TYPE_1();
o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory);
return o;
}
/* accessor methods */
public String getMessage() throws SQLException {
return (String) _struct.getAttribute(0);
}
public void setMessage(String message) throws SQLException {
_struct.setAttribute(0, message);
}
}
命名不太规范哈 , 还是见谅 ,
一些说明
这篇文章主要是给自己的一个学习笔记 , 代码编写规范 , 详细的文档说明由于我的准备不足很遗憾的告诉大家不太好,花了几天时间研究的这么一个东西 , 参阅了一些博客,查阅了一些Oracle 的官方文献 , 还是略显不够成熟的一个东西 , 但是我提供的代码部署 , 毫无疑问是可以跑起来的,这点放心 ,
一些完善
当然我们可以对相关的代码进行封装 , 比如尝试和spring 进行集成 , 在IOC容器中对其深度管理 ,还可以对Oracle AQ 的入队操作完全封装为存储过程 , 让触发器来调用存储过程,尝试消息的入队操作 , 数据库端也可以有更多的完善 , 等等
消息载荷的Oracle类型到JAVA类型的转换
前面我们提到如何进行进行类型转换 , 我只是一味的提供了代码 , 这段代码为什么可以这样写 , 如果我的消息载荷里有多个类型呢?
根据我在Oracle 官方查阅到的资料 , 可能啊 , 只是可能 , 在Oracle 11G 之前Oracle提供了 jpublisher 工具进行类型转换 , 你需要配置一些数据库连接的相关配置 , 然后告诉Oracle你需要对那个"TYPE" 或者说哪个消息载荷进行转换 , 然互jpublisher会输出一段java代码给你使用 , 目前从网络上我了解到的相关资料 , Oracle已经停止了该工具的下载 , 至少我在oracle 官方上没有下载成功 , 提示我需要同意他的一些协议 , 但是事实上并没有相关条款的弹出 , 我也无法同意 , 诚然 , 我也无法下载
但是关于jpublisher 的相关文档Oracle 上面我们还是可以查到 , 想了解或者已经在其他的地方获得了jpublisher jar包的同学可以去阅读一下相关的文档
后面我还了解到在11g oracle database 的安装中会附送jpublisher 的相关jar 和jplus 的相关的jar,至于如何找到这些东西 , 我了解还不够深入 , 还是去看关于这方面的相关文档
笔者是如何写出上面的类型装换代码的呢? 我是参阅别人的代码 , ,然后改造的自己的代码 , 细心的同学可以去看看这个博文 , 然后你也许能纯手打 , 或者定制自己的类型转换代码 , 都要规则 , 或者说是规律 , 应该很容易学习
http://blog.csdn.net/peigen521/article/details/26993683
关于消息到达的延迟 ,