oracle dbms_aq,oracle – dbms_aq.dequeue_array,第一条消息返回两次
介绍
使用Oracle Advanced Queuing方法时,我在Oracle SQL Server上遇到了一个非常奇怪的行为(确切地说:Oracle Database 11g企业版11.2.0.4.0版 – 64位生产版).
问题
错误是我将X消息排队,但是dequeue_array返回X 1消息,第一条消息重复(如MessageId所示).
复制:
我能够编写一些简单的PoC来重现错误.本代码非常简单,入队/出队的东西是标准的Oracle AQ.代码执行以下步骤两次(测试运行):
>清除队列表
>排队X消息
>使用dbms_aq.dequeue_array调用使所有消息出列
>检查已出列的消息数
在新连接上运行POC时,第一次运行成功而没有错误,但每次后续运行都失败.之后,当使用相同的连接时,每次执行脚本时,它都会在两次测试运行中失败.
到目前为止我尝试了什么:
>在“新”连接上运行此脚本:仅第一次运行失败
>在同一连接上执行脚本的任何其他操作:所有运行都失败
>使用/创建新队列时:只有第一次运行失败
>使用“从< queue_table>中删除”时而不是dbms_aqadm.purge_queue_table():一切都很好
>当使用“正常”一个一个出列时:每次都很好
结论:
我既不能解释这种行为,也不能在我的代码中找到错误.请看一下它,它应该可以在你最喜欢的sql客户端中直接执行(用PL / SQL Developer测试).
如果您需要任何进一步的信息或在让PoC工作时遇到问题,请问,我会定期检查这个帖子.我试图使PoC尽可能可读,包括关于正在发生的事情的详细输出.
码:
declare
C_QueueName constant varchar2(32767) := 'TEST_QUEUE';
C_QueueTable constant varchar2(32767) := 'TEST_Q_TABLE';
C_MsgCount constant pls_integer := 1;
C_TestRuns constant pls_integer := 2;
C_DequeueArraySize constant pls_integer := 10;
/*
* Create the queue and the queue table used for theses tests
*/
procedure CreateQueueIfMissing is
L_Present pls_integer;
begin
dbms_output.put_line('START CreateQueueIfMissing');
execute immediate 'select count(*) from USER_OBJECTS where OBJECT_NAME = ''' || C_QueueName || ''' and OBJECT_TYPE = ''QUEUE''' into L_Present;
if L_Present = 1 then
dbms_output.put_line('Skipping queue creation, already present.');
dbms_output.put_line('END CreateQueueIfMissing');
return;
end if;
dbms_output.put_line(' Creating queue table ' || C_QueueTable);
DBMS_AQADM.CREATE_QUEUE_TABLE(queue_table => C_QueueTable
,storage_clause => 'LOGGING NOCACHE NOPARALLEL MONITORING'
,sort_list => 'priority,enq_time'
,multiple_consumers => false
,queue_payload_type => 'SYS.AQ$_JMS_BYTES_MESSAGE'
,comment => 'Queue for messages');
dbms_output.put_line(' Creating queue ' || C_QueueName);
DBMS_AQADM.CREATE_QUEUE(queue_name => C_QueueName
,queue_table => C_QueueTable
,max_retries => 8640
,retry_delay => 30
,comment => 'Queue for messages');
dbms_output.put_line(' Starting queue ' || C_QueueName);
DBMS_AQADM.START_QUEUE(queue_name => C_QueueName);
dbms_output.put_line('END CreateQueueIfMissing');
end CreateQueueIfMissing;
-- ================================================================================================
/*
* This procedure is the root of all evil.
* The error only occurs when using the purge_queue_tables procedure.
* When using a normal "delete from " then everything is just fine.
*/
procedure CleanQueueTable is
L_PurgeOptions dbms_aqadm.aq$_purge_options_t;
L_Count pls_integer;
begin
dbms_output.put_line('START CleanQueueTable');
execute immediate 'select count(*) from ' || C_QueueTable into L_Count;
dbms_output.put_line(' Messages in queue table BEFORE purge: ' || L_Count);
dbms_aqadm.purge_queue_table(queue_table => C_QueueTable
,purge_condition => null
,purge_options => L_PurgeOptions);
execute immediate 'select count(*) from ' || C_QueueTable into L_Count;
dbms_output.put_line(' Messages in queue table AFTER purge: ' || L_Count);
dbms_output.put_line('END CleanQueueTable');
end CleanQueueTable;
-- ================================================================================================
/*
* Enqueue the configured count of messages on the queue
*/
procedure EnqueueMessages is
L_BodyId pls_integer;
L_Msg sys.aq$_jms_bytes_message;
L_MsgId raw(16);
L_Count pls_integer;
L_EnqueueOptions DBMS_AQ.ENQUEUE_OPTIONS_T;
L_MessageProperties DBMS_AQ.MESSAGE_PROPERTIES_T;
begin
dbms_output.put_line('START EnqueueMessages');
execute immediate 'select count(*) from ' || C_QueueTable into L_Count;
dbms_output.put_line(' Messages in queue table BEFORE enqueue: ' || L_Count);
for i in 1 .. C_MsgCount
loop
dbms_output.put_line(' Construct #' || i);
L_Msg := sys.aq$_jms_bytes_message.construct;
-- set the JMS header
L_Msg.set_type('JmsBytesMessage');
L_Msg.set_userid(1);
L_Msg.set_appid('test');
L_Msg.set_groupid('cs');
L_Msg.set_groupseq(1);
-- set JMS message content
L_BodyId := L_Msg.clear_body(-1);
L_Msg.write_bytes(L_BodyId, to_blob(utl_raw.cast_to_raw('Lorem Ipsum')));
L_Msg.flush(L_BodyId);
L_Msg.clean(L_BodyId);
dbms_output.put_line(' Enqueue #' || i);
DBMS_AQ.ENQUEUE (queue_name => C_QueueName
,enqueue_options => L_EnqueueOptions
,message_properties => L_MessageProperties
,payload => L_Msg
,msgid => L_MsgId);
end loop;
execute immediate 'select count(*) from ' || C_QueueTable into L_Count;
dbms_output.put_line(' Messages in queue table AFTER enqueue: ' || L_Count);
dbms_output.put_line('END EnqueueMessages');
end EnqueueMessages;
-- ================================================================================================
/*
* Dequeues messages using dequeue_array from the configured queue.
*/
procedure DequeueMessages is
L_DequeueOptions dbms_aq.dequeue_options_t;
L_MsgPropArr dbms_aq.message_properties_array_t := dbms_aq.message_properties_array_t();
L_PayloadArr sys.aq$_jms_bytes_messages;
L_MsgIdArr dbms_aq.msgid_array_t;
L_MsgCnt pls_integer := 0;
L_Count pls_integer;
begin
dbms_output.put_line('START DequeueMessages');
execute immediate 'select count(*) from ' || C_QueueTable into L_Count;
dbms_output.put_line(' Messages in queue table BEFORE dequeue: ' || L_Count);
L_MsgCnt := dbms_aq.dequeue_array(queue_name => C_QueueName
,dequeue_options => L_DequeueOptions
,array_size => C_DequeueArraySize
,message_properties_array => L_MsgPropArr
,payload_array => L_PayloadArr
,msgid_array => L_MsgIdArr);
execute immediate 'select count(*) from ' || C_QueueTable into L_Count;
dbms_output.put_line(' Messages in queue table AFTER dequeue: ' || L_Count);
dbms_output.put_line(' Expected: ' || C_MsgCount || ', Received: ' || L_MsgCnt);
if C_MsgCount != L_MsgCnt then
dbms_output.put_line(' *****************************************');
dbms_output.put_line(' TOO MANY ITEMS DEQUEUED?!?');
dbms_output.put_line(' *****************************************');
for i in 1 .. L_MsgCnt
loop
dbms_output.put_line(' #' || i || ' MsdId=' || L_MsgIdArr(i));
end loop;
end if;
dbms_output.put_line('END DequeueMessages');
end DequeueMessages;
-- ================================================================================================
/*
* This is the testcase
*/
procedure RunTestCase is
begin
CreateQueueIfMissing;
for i in 1 .. C_TestRuns
loop
dbms_output.put_line(null);
dbms_output.put_line('=========== START test run #' || i || '===========');
CleanQueueTable;
EnqueueMessages;
DequeueMessages;
end loop;
end;
-- ================================================================================================
begin
RunTestCase;
end;
示例输出:
START CreateQueueIfMissing
Skipping queue creation, already present.
END CreateQueueIfMissing
=========== START test run #1===========
START CleanQueueTable
Messages in queue table BEFORE purge: 0
Messages in queue table AFTER purge: 0
END CleanQueueTable
START EnqueueMessages
Messages in queue table BEFORE enqueue: 0
Construct #1
Enqueue #1
Messages in queue table AFTER enqueue: 1
END EnqueueMessages
START DequeueMessages
Messages in queue table BEFORE dequeue: 1
Messages in queue table AFTER dequeue: 0
Expected: 1, Received: 1
END DequeueMessages
=========== START test run #2===========
START CleanQueueTable
Messages in queue table BEFORE purge: 0
Messages in queue table AFTER purge: 0
END CleanQueueTable
START EnqueueMessages
Messages in queue table BEFORE enqueue: 0
Construct #1
Enqueue #1
Messages in queue table AFTER enqueue: 1
END EnqueueMessages
START DequeueMessages
Messages in queue table BEFORE dequeue: 1
Messages in queue table AFTER dequeue: 0
Expected: 1, Received: 2
*****************************************
TOO MANY ITEMS DEQUEUED?!?
*****************************************
#1 MsdId=2949A0FF2EE456A7E0540010E0467A30
#2 MsdId=2949A0FF2EE456A7E0540010E0467A30
END DequeueMessages
oracle dbms_aq,oracle – dbms_aq.dequeue_array,第一条消息返回两次相关推荐
- oracle如何删除重复数据第一条,oracle删除重复数据保留第一条记录
oracle删除重复数据保留第一条记录 1.查找表中多余的重复记录,重复记录是根据单个字段(Id)来判断select * from 表 where Id in (select Id from 表 gr ...
- ORACLE分组排序后获取第一条和最后一条值
ORACLE分组排序后获取第一条和最后一条值 参考链接 实践 后记 参考链接 ORACLE分组排序后获取第一条和最后一条值 实践 wx_user的手机号有部分有问题,发生了串登录.原本一个用户对应一个 ...
- java tcp发消息给硬件_java – TCP客户端/服务器通信只发送第一条消息?
我在java中设置一个简单的TCP客户端服务器交互. 服务器: 服务器是用Java编写的桌面客户端: import java.io.BufferedReader; import java.io.Dat ...
- Java黑皮书课后题第9章:**9.12(几何:交点)假设两条线段相交。第一条线段的两个端点是(x1, y1)和(x2, y2),第二条线段的两个端点是(x3, y3)和(x4, y4)
Java黑皮书课后题第9章:**9.12(几何:交点)假设两条线段相交.第一条线段的两个端点是(x1, y1)和(x2, y2),第二条线段的两个端点是(x3, y3)和(x4, y4) 题目 破题 ...
- oracle 分组排序后取第一条_关于oracle中位图索引的探讨:概念、原理、优缺点...
概述 oracle索引主要分为以下几种: 1. b-tree索引 Oracle数据库中最常见的索引类型是b-tree索引,也就是B-树索引,以其同名的计算科学结构命名.CREATE INDEX语句时, ...
- oracle和sql server取第一条记录的区别以及rownum详解
我们知道学生可能有重名的情况,那么当重名的时候假设只需要取得重名结果集中的第一条记录. sql server:select top(1) num,Name from M_Student where n ...
- oracle sql取查询结果第一条,SQL获取第一条记录的方法(sqlserver、oracle、mysql数据库)...
Sqlserver 获取每组中的第一条记录 在日常生活方面,我们经常需要记录一些操作,类似于日志的操作,最后的记录才是有效数据,而且可能它们属于不同的方面.功能下面,从数据库的术语来说,就是查找出每组 ...
- rocketmq发送第一条消息(三)
直接上代码 导包,pom.xml <dependency><groupId>org.apache.rocketmq</groupId><artifactId& ...
- Oracle取排序的第五条数据,OVER(PARTITION BY)函数介绍 【oracle中按A分组按B排序,再取B中第一条数据的查询】...
目录 一.小案例: school表中有①id 序号②class 班级 ③score成绩 三个字段, 使用oracle实现按照班级分区,然后取班级中的第一名. 1.1测试数据如下: --创建学校表sch ...
最新文章
- node.js linux shell,bash – Node.js Shell脚本和参数
- 基于libsvm的中文文本分类原型
- 学习笔记Spark(四)—— Spark编程基础(创建RDD、RDD算子、文件读取与存储)
- 从Activity中返回数据
- linux中断处理体系结构
- Win8下用DOSBox编写汇编语言
- Win7从VHD中启动 如何扩充虚拟磁盘
- 电脑必备必装的软件工具神器,强烈推荐
- ext3转化为ext4
- 韦东山freeRTOS系列教程之【第八章】事件组(event group)
- Mono.Cecil FAQ文档翻译
- 机器学习-朴素贝叶斯(高斯、多项式、伯努利)
- AD软件生成gerb文件方法参考
- 【面试题】HTML篇(一)
- ConstraintLayout已经2.0了,你不来了解一下吗?
- QVM 实操记 - 18.12.28
- Mac上播放 swf 格式文件 小技巧
- 聊天框体实现:好友填充框
- Cow Gymnastics//队列//排位1
- OPENAPI3.0 与 SpringBoot 开发实战: 新型高效开发模式,实现代码与API分离,高效开发,开发必看!!!
热门文章
- android使用airpods软件,安卓怎么使用airpods?安卓上兼容AirPodsPro软件方法教程[多图]...
- 基于Android平台高校学生综合素质测评系统
- 关于Object.defineProperty的几个坑
- Java NIO持续触发读事件的解决方法
- 获猎豹千万级融资 3年研发科幻版《我的世界》:可造星际战舰
- 华为云数据库赋能数字化转型,为让云原生数据库走进千行百业
- windows 下接入西克激光LMS151
- 展讯平台功耗调试记录
- APP如何发布到Google play 商店?以及有哪些需要注意的点
- 甘肃政协委员:用对“领头羊”破乡村空壳合作社