SAP LDQ本地数据队列

9 篇文章 2 订阅

简述

        qRFC NoSend 的重新实现和重新设计,基于更高效的数据模型

        LDQ 允许应用程序记录可以被接收应用程序读取的数据( pull原理)您应该确保在读取数据时它只能被调用一次,并且按照它的创建顺序( 按顺序恰好一次)。LDG 的访问遵循 FIFO 原则(先进先出 )。

        如果您使用移动客户端能够在需要时从相关服务器调用数据,可以使用LDQ。

        LDQ 使用队列组织不同的接收者。管理和监控基于这些队列。您可以为一个客户端创建一个或多个队列,但不同的客户端不能使用同一个队列。

        LDQ 为开发人员提供了一个 API,用于允许调用者记录数据,然后由被调用的应用程序或通用解决方案(例如, 移动基础设施)的框架层读取。

        API 只能在本地使用。要记录的数据以字符串( 字符或二进制)的形式传输。

        由于还可以为多个客户端定义记录的数据,LDQ 确保数据只存储一次,并且在队列中对这些数据进行正确的引用。

        队列彼此独立。这意味着可以基于一个队列,按照记录的顺序,只读取一次数据。各种队列之间没有隐含的数据依赖关系。

准备

        删除程序 RS_LDQ_DAEMON 设计用于定期删除已处理的单元。该程序在后台异步运行。您可以使 用程序 RSLDQREORG 将此删除程序安排为后台作业。

监控

        事务 SLDQMON 调用 LDQ (本地数据队列)监视器。

特点

        基于后台远程函数调用 (bgRFC) 的 NoSend 场景。bgRFC NoSend场景使用链表作为队列。

        基于后台远程函数调用 (bgRFC) 的NoSend场景。迄今为止,qRFC NoSend方案一直用于 MMW。

        在规范阶段,构建了 LDQ 和两种替代设计理念的原型,并比较了各种数据量的读取和写入。事实证明,LDQ 选项在性能和可维护性方面都优于其他选项(参见 bgRFC NoSend MMW 性能数据)。

开发

         IF_LDQ_READER 接口中的 CONFIRM_QUEUE_UNITS 方法外,LDQ类的所有方法都需要一个 Explicit Commit才能将它们的工作持久化到数据库中。此方法执行 隐式提交。

         CL_LDQ_APPLICATION 类是 LDQ 读取器和 LDQ 写入器对象的工厂类。

方法

可见度/级别

描述

GET_WRITER

公共静态

该方法创建一个 LDQ writer 对象或获取一个现有的。该方法需要本地数据队列的应用程序名称并返回接口引用。

GET_READER

公共静态

该方法创建一个 LDQ 读取器对象或获取现有的读取器对象。该方法需要本地数据队列的应用程序名称并返回接口引用。

        写入器类CL_LDQ_WRITER 用于初始化 LDQ 写入用例的队列表。实现接口 IF_LDQ_WRITER。

方法

可见度/级别

描述

SET_QUEUE_NAMES

公共实例

该方法创建一个 LDQ 单元写入器对象。该方法需要一个 LDQ 队列名称表并返回一个接口引用。

        单元写入器类CL_LDQ_UNIT_WRITER,将 LDQ 队列持久保存在数据库中。该类实现接口 IF_LDQ_UNIT_WRITER。

方法

可见度/级别

描述

GET_NEXT_CONTENT

公共实例

创建下一个单元的内容。该方法返回一个接口引用。

CLASS_CONSTRUCTOR

公共静态

类构造函数。

ON_COMMIT

公共静态

将创建的 LDQ 单元持久保存在数据库中。

ON_ROLLBACK

公共静态

回滚创建的 LDQ 单元。

AFTER_COMMIT

公共静态

删除内部表。

        单元内容编写器类 CL_LDQ_UNIT_CONTENT_WRITER,将有效负载写入 LDQ 单元。该类实现接口 IF_LDQ_UNIT_CONTENT_WRITER。

方法

可见度/级别

描述

SET_CDATA

公共实例

该方法写入类似字符的数据。该方法需要一个字符串。如果单位无效,该方法将引发异常。

SET_XDATA

公共实例

该方法写入二进制数据。该方法需要一个字节串。

GET_UNIT_ID

公共实例

该方法读取当前的单元 ID。

SET_DESCRIPTION

公共实例

该方法将附加描述写入单元。该方法需要一个短字符串。

        读取器类 CL_LDQ_READER,用于初始化 LDQ 读取用例的队列表。该类实现接口 IF_LDQ_READER。

        此类中的 CONFIRM_QUEUE_UNITS 方法是唯一执行 隐式提交的 LDQ 方法。此类和其他 LDQ 类的所有其他方法都需要 显式提交才能将其工作持久保存在数据库中。

方法

可见度/级别

描述

SET_QUEUE_NAME

公共实例

该方法创建一个 LDQ 单元读取器对象。该方法需要一个 LDQ 队列名称并返回一个接口引用。当队列被另一个读取器使用时,该方法会引发异常。

SET_QUEUE_NAME_BY_OFFSET

公共实例

为给定队列创建一个 LDQ 单元读取器对象,该队列具有给定的队列读取计数器偏移量。如果偏移量大于当前读取计数器(= 尝试跳过读取某些单元),则会引发异常。如果偏移量小于当前顶部计数器(= 尝试读取已确认的单元),则会引发异常。

CONFIRM_QUEUE_UNITS

公共实例

标记删除已读取到给定序列号的单元。如果偏移计数器大于当前读取计数器(= 尝试确认从未读取过的单元),则会引发异常。如果偏移计数器小于当前的顶部计数器(= 尝试确认已确认的单位),则会引发异常。

注意:此方法执行 隐式提交

        单元读取器类 CL_LDQ_UNIT_READER,为特定 LDQ 队列提供句柄,以便读取一个或多个 LDQ 单元。该类实现接口 IF_LDQ_UNIT_READER。

方法

可见度/级别

描述

GET_NEXT_STATES

公共实例

读取下一个单元的状态。该方法需要读取的单元数并返回单元状态表。

GET_NEXT_CONTENTS

公共实例

读取下一个单元的内容。该方法需要读取的单元数并返回单元内容表。

GET_TOTAL_NUMBER_OF_UNITS

公共实例

获取队列中的条目总数。

CONFIRM

公共实例

标记删除已读取的单元。

CHECK_READ_SEQUENCE

私有静态

验证读取单元的顺序。

ON_ROLLBACK

公共静态

回滚称为 LDQ 单元。

AFTER_COMMIT

公共静态

删除内部表。

ON_COMMIT

公共静态

删除数据库中读取的 LDQ 单元。LDQ 类的所有方法都通过 Explicit Commit将其工作保存在数据库中,但 IF_LDQ_READER 接口中的 CONFIRM_QUEUE_UNITS 方法除外,该方法执行 Implicit Commit。

        单元状态读取器类 CL_LDQ_UNIT_STATE_READER,CL_LDQ_UNIT_STATE_READER类读取一个或多个LDQ单元的状态数据,即单元大小、单元格式和单元id。该类实现接口 IF_LDQ_UNIT_STATE_READER。

方法

可见度/级别

描述

GET_FORMAT

公共实例

该方法返回 LDQ 单元数据的格式。

GET_UNIT_ID

公共实例

该方法返回 LDQ 单元的 Unit-ID。

GET_SEQUENCE_NUMBER

公共实例

该方法返回一个 LDQ 单元的序列号。

GET_SUCCESSOR_COUNT

公共实例

该方法返回队列中跟随单元的数量。

GET_SIZE

公共实例

该方法返回 LDQ 单元数据的大小。

GET_DESCRIPTION

公共实例

该方法返回 LDQ 单元的附加描述。

CHECK_COMMIT_ROLLBACK

私有实例

该方法检查LDQ单元是否有效。

        单元内容读取器类 CL_LDQ_UNIT_CONTENT_READER,CL_LDQ_UNIT_CONTENT_READER 类读取指定 LDQ 队列中一个或多个 LDQ 单元的有效负载。

方法

可见度/级别

描述

GET_CDATA

公共实例

该方法读取类似字符的数据。该方法返回一个字符串。

GET_XDATA

公共实例

该方法读取二进制数据。该方法返回一个字节字符串。

GET_FORMAT

公共实例

该方法返回 LDQ 单元数据的格式。

GET_UNIT_ID

公共实例

该方法返回 LDQ 单元的 Unit-ID。

GET_SEQUENCE_NUMBER

公共实例

该方法返回一个 LDQ 单元的序列号。

GET_SUCCESSOR_COUNT

公共实例

该方法返回队列中跟随单元的数量。

GET_DESCRIPTION

公共实例

该方法返回 LDQ 单元的附加描述。

GET_SIZE

公共实例

该方法返回 LDQ 单元数据的大小。

示例

        LDQ写入数据示例

*a) Input parameters:
PARAMETERS: ap_name  TYPE ldq_application_name DEFAULT 'Perf_TEST',
            qp_name  TYPE ldq_queue_name DEFAULT 'LDQ_TEST_',
            n_queues TYPE i DEFAULT 5,
            n_unit   TYPE i DEFAULT 100,
            u_size   TYPE i DEFAULT 2,
            b_data   AS CHECKBOX.

*b) Variable D eclarations:
DATA: l_ldq_write               TYPE REF TO if_ldq_writer,
      l_ldq_unit_writer         TYPE REF TO if_ldq_unit_writer,
      l_ldq_unit_content_writer TYPE REF TO if_ldq_unit_content_writer.

DATA: l_queue_name_tab TYPE ldq_queue_name_tab,
      l_queue_name     TYPE ldq_queue_name.

DATA: l_cdata TYPE string.
DATA: l_cdata2 TYPE string.

DATA: l_seq_nr TYPE ldq_unit_id.
DATA: l_queue_nr(4) TYPE n.
DATA: l_size TYPE i.
DATA: l_xdata TYPE xstring.
DATA: l_times TYPE i.
DATA: l_rt_ubegin TYPE i,
      l_rt_uend   TYPE i,
      l_rt_qbegin TYPE i,
      l_rt_qend   TYPE i.

*c) Creation of queue names:

DO n_queues TIMES.

  l_queue_nr = sy-index.
  CONCATENATE qp_name l_queue_nr INTO l_queue_name.
  CONDENSE l_queue_name NO-GAPS.
  APPEND l_queue_name TO l_queue_name_tab.

  WRITE: / 'Qname: ', l_queue_name.

ENDDO.

ULINE.

*d) Creation of binary payload:

IF b_data IS NOT INITIAL.

  l_cdata2 = '01234'.

  DO 100 TIMES.
    CONCATENATE l_cdata2 l_cdata INTO l_cdata.
  ENDDO.

  l_xdata = l_cdata.
  l_size = xstrlen( l_xdata ).
  l_times = u_size * 1000 / l_size.

  CLEAR l_cdata2.
  DO l_times TIMES.
    CONCATENATE l_cdata2 l_cdata INTO l_cdata2.
  ENDDO.

  l_xdata = l_cdata2.
  l_size = xstrlen( l_xdata ).

ELSE.

  IF cl_abap_char_utilities=>charsize = 1.
    l_cdata2 = '0123456789'.
  ELSE.
    l_cdata2 = '01234'.
  ENDIF.

  DO 100 TIMES.
    CONCATENATE l_cdata2 l_cdata INTO l_cdata.
  ENDDO.

  l_size = u_size - 1.
  DO l_size TIMES.
    CONCATENATE l_cdata l_cdata INTO l_cdata.
  ENDDO.

ENDIF.

*e) Creation of LDQ application object:

l_ldq_write = cl_ldq_application=>get_writer( ap_name ).

*f) Initialisation of the target queues for the units in this application:

l_ldq_unit_writer = l_ldq_write->set_queue_names( l_queue_name_tab ).

GET RUN TIME FIELD l_rt_ubegin. "aktuelle Zeit holen

DO n_unit TIMES.

*g) Request a unit content, i. e. status and payload of a unit, for inserting into specified queues:
  l_ldq_unit_content_writer = l_ldq_unit_writer->get_next_content( ).

*h) Ask for sequence number of this content:
*  l_seq_nr = l_ldq_unit_content_writer->get_sequence_number( ).

*i) Insert the relevant data into the content:
  IF b_data IS INITIAL.

* character payload
    l_ldq_unit_content_writer->set_cdata( l_cdata ).

  ELSE.

* binary payload
    l_ldq_unit_content_writer->set_xdata( l_xdata ).

  ENDIF.

ENDDO.

*j) Persist unit contents into database:
COMMIT WORK. 

        监控查看数据处理状态

         LDQ读取示例

*a) Input parameters:
PARAMETERS: ap_name  TYPE ldq_application_name DEFAULT 'Perf_TEST',
            qp_name  TYPE ldq_queue_name DEFAULT 'LDQ_TEST_',
            n_queues TYPE i DEFAULT 5,
            n_units  TYPE i DEFAULT 10,
            n_times  TYPE i DEFAULT 1.

*b) Declarations:
DATA: l_ldq_reader      TYPE REF TO if_ldq_reader,
      l_ldq_unit_reader TYPE REF TO if_ldq_unit_reader.
DATA: l_queue_name_tab TYPE ldq_queue_name_tab,
      l_queue_name     TYPE ldq_queue_name.
DATA: l_xdata TYPE xstring,
      l_cdata TYPE string.
DATA: l_size TYPE i.
DATA: l_content_tab TYPE ldq_unit_content_reader_tab.
DATA: l_state_tab TYPE ldq_unit_state_reader_tab.
DATA: l_del TYPE i.
DATA: l_seq_nr TYPE ldq_unit_id.
DATA: l_queue_nr(4) TYPE n.
DATA: l_lines TYPE i.
DATA: l_last_lines TYPE i.
DATA: l_unit TYPE i.
DATA: l_state_wa   TYPE REF TO if_ldq_unit_state_reader,
      l_content_wa TYPE REF TO if_ldq_unit_content_reader.

DATA: l_format TYPE ldq_data_format.
DATA: l_next_state_nr TYPE i.
DATA: l_number TYPE i.

TYPES: BEGIN OF lt_my_unit_reader,
         unit_reader TYPE REF TO if_ldq_unit_reader,
         queue_name  TYPE ldq_queue_name,
       END OF lt_my_unit_reader.

DATA: l_my_unit_reader_tab TYPE TABLE OF lt_my_unit_reader.
DATA: l_my_unit_reader TYPE lt_my_unit_reader.

FIELD-SYMBOLS: <l_content_wa> TYPE REF TO if_ldq_unit_content_reader.
FIELD-SYMBOLS: <l_state_wa> TYPE REF TO if_ldq_unit_state_reader.

*c) Creation of queue names:

CLEAR: l_queue_name_tab[], l_content_tab[].

DO n_queues TIMES.
  l_queue_nr = sy-index.
  CONCATENATE qp_name l_queue_nr INTO l_queue_name.
  CONDENSE l_queue_name NO-GAPS.
  APPEND l_queue_name TO l_queue_name_tab.
ENDDO.

LOOP AT l_queue_name_tab INTO l_queue_name.

*  d) creation of ldq application object:
  l_ldq_reader = cl_ldq_application=>get_reader( ap_name ).

* Creation of LDQ queu objects for each queue name
  l_my_unit_reader-unit_reader = l_ldq_reader->set_queue_name( l_queue_name ).
  l_my_unit_reader-queue_name = l_queue_name.
  APPEND l_my_unit_reader TO l_my_unit_reader_tab.

ENDLOOP.

*

* Read the block units over all queues n_times
DO n_times TIMES.
  LOOP AT l_my_unit_reader_tab INTO l_my_unit_reader.

*    e) GET n_units in one block:
    l_content_tab = l_my_unit_reader-unit_reader->get_next_contents( n_units ).
    l_unit = lines( l_content_tab ).

*    f) retrieve contained information out of content object:
    CLEAR l_number.
    WRITE: / l_unit, 'Qname:', l_my_unit_reader-queue_name.

    LOOP AT l_content_tab ASSIGNING <l_content_wa>.

      l_format = <l_content_wa>->get_format( ).
      IF l_format = 'C'.
        l_cdata = <l_content_wa>->get_cdata( ).
      ELSE.
        l_xdata = <l_content_wa>->get_xdata( ).
      ENDIF.

      l_seq_nr = <l_content_wa>->get_sequence_number( ).
      l_size = <l_content_wa>->get_size( ).
      l_number = l_number + 1.

      WRITE: /10 'number:', l_number, 'sequence number =', l_seq_nr, 'size in kb:', l_size.

    ENDLOOP.

*    g) confirm the READ unit in the database:
    l_my_unit_reader-unit_reader->confirm( ).

*    h) persist the READ status of ldq DATA into the database:
    COMMIT WORK.

  ENDLOOP.
ENDDO.

        读取效果,读取完成后,在SLDQMON中可查看已被移除,如果需要读取完成后保留,需要使用方法l_ldq_reader->confirm_queue_units。

 https://blog.csdn.net/xiefireworks/article/details/126326006

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值