同步RFC(sRFC)是RFC的最原始版本,其执行基于同步通信模式,远程调用时,通信双方的系统必须均可用,调用程序等待远程功能处理结束并返回结果。
调用语法:
CALL FUNCTION rfm_name
DESTINATION dest
[EXPORTING p1 = a1...]
[IMPORTING p1 = a1...]
[CHANGING p1 = a1...]
[TABLE t1 = itab1...]
[EXCEPTIONS exc1 = e1...]
同步调用时,CALL FUNCTION语句中除DESTINATION外没有其他RFC附加项,可以指定所有类型的参数,但各种参数均不能为引用传递。
2.异步RFC
在异步RFC(aRFC)中,执行并不依赖于RFC服务器系统的可用性。被调用的远程功能启动之后,调用程序继续运行,远程功能和调用程序相互分离。远程功能的结果可以稍后接收。
调用语法:
CALL FUNCTION rfm_name
STARTING NEW TASK taskname
[DESTINATION dest] ‘在异步RFC调用过程中,不是必需项’
[EXPORTING p1 = a1...]
[TABLES t1 = itab1...]
[EXCEPTIONS exc1 = e1]
附加项STARTING NEW TASK指明异步调用模式,任务名称可以指定,通常对于不同的异步调用,应指定不同的任务名称。功能模块在新的工作过程中执行,也可以在后台模式处理异步调用过程。需注意的是,在后台处理时,每个异步RFC调用也将占据一个对话工作过程。
2.1调用参数
异步RFC调用过程只能使用TABLES、EXPOTING(对应功能模块设定中的Import参数)和EXCEPTIONS参数。调用程序并不等待该模块的返回结果,因而不能指定IMPORTING参数,即不能直接接收从被调用功能中的返回信息,但可以在后续的独立回调子程序中处理。而且,调用的同时只能接收系统标准异常COMMUNICATION_FAILURE和SYSTEM_FAILURE,对于功能模块中抛出的其它特定异常则不能直接接收也需要在回调子程序中处理。
异步RFC也要求RFC服务器系统在调用时可用,被调用的功能模块将立即启动并并运行。与同步RFC调用的区别在于,调用程序不等待远程调用结果,而是继续执行,远程功能处理与调用程序的处理过程相分离,功能返回结果可在后续过程中被接收。
异步RFC调用过程也支持远程对话处理如下图,在异步RFC调用时,系统总是打开新的工作过程,因而如果被调用功能模块中包含对话过程(即屏幕调用处理),则在该功能模块执行时,在调用系统中将出现新的外部会话窗口,用户可以和远程系统交互对话,并允许在调用程序对话和被调用程序对话之间来回切换。由于SAP限定同一个登录中最多只打开6个外部会话,因而如果调用功能时打开的会话数目已达6个,则在试图打开新窗口时将触发SYSTEM_FAILURE异常。
异步RFC调用时,如果对RFM进行调试,调用程序本身的调试会话不进入RFM内部。同时,系统也打开新的外部会话,单独增加一个
调试窗口,进行目标系统中RFM的调试。
如果需要在异步RFC模式下接收远程模块的返回结果或特定异常,可以通过调用语句中的附加项
PERFORMING return_form ON END OF TASK实现。
CALL FUNCTION rfm_name
SATRTING NEW TASK taskname
PERFORMING return_form ON END OF TASK
...
其中指定的子程序必须存在于调用程序中,并包含语句:
FORM return_form USING taskname.
...
RECEIVE RESULTS FROM FUNCTION rfm_name
...
ENDFORM.
当被调用功能模块结束后,调用程序的下一个对话步骤(如AT USER-COMMAND) 将引导系统进入回调子程序RETURN_FORM以接收远程调用
的结果,如下图。该子程序必须包含一个任意名称、类型的形式参数,用于帮助调用程序确定当前刚刚结束并返回的异步RFC调用,
以接收对应异步RFC调用的任务名称。
下面来看一个关于异步RFC的例子。
程序代码:
REPORT z_test .
DATA: user_addr TYPE user_addr,
system_id TYPE sysysid,
user_para LIKE TABLE OF user05 WITH HEADER LINE,
mag_text(128).
CALL FUNCTION 'ZRFC_USER_READ'
STARTING NEW TASK 'B1'
DESTINATION 'P560q_DEV_00'
PERFORMING return_user ON END OF TASK
EXPORTING
user_name = 'NAME'
TABLES
user_para = user_para.
IF sy-subrc = 0.
WRITE: 'Wait for reply'.
ELSE.
WRITE 'other error'.
ENDIF.
IF user_para IS INITIAL.
WRITE:/ 'Destination not ready yet.'.
ELSE.
WRITE:/ 'Destination is reached.'.
ENDIF.
AT USER-COMMAND.
IF sy-ucomm = 'OKCD'.
LOOP AT user_para.
WRITE:/ user_para-parid,
user_para-parva.
ENDLOOP.
ENDIF.
*---------------------------------------------------------------------*
* FORM return_user *
*---------------------------------------------------------------------*
* ........ *
*---------------------------------------------------------------------*
* --> TASKNAME *
*---------------------------------------------------------------------*
FORM return_user USING taskname.
RECEIVE RESULTS FROM FUNCTION 'ZRFC_USER_READ'
IMPORTING
user_addr = user_addr
system_id = system_id
TABLES
user_para = user_para.
SET USER-COMMAND 'OKCD'.
ENDFORM.
rfc代码:
FUNCTION ZRFC_USER_READ.
*"----------------------------------------------------------------------
*"*"Local interface:
*" IMPORTING
*" VALUE(USER_NAME) TYPE XUBNAME
*" EXPORTING
*" VALUE(USER_ADDR) TYPE USR03
*" VALUE(SYSTEM_ID) TYPE SYSYSID
*" TABLES
*" USER_PARA STRUCTURE USR05
*"----------------------------------------------------------------------
select single * into user_addr from usr03
where bname = user_name.
select * into table user_para from usr05
where bname = user_name.
system_id = sy-sysid.
ENDFUNCTION.
此外,调用程序中的AT USER-COMMAND语句有双重作用,即在RFM执行结束之后引导主程序进入子程序,同时又通过sy-ucomm接受子程序中设定的OK代码。子程序中的RECEIVE RESULTS FROM FUNCTION 从RFM中接收结果.
2.2 异步调用中的等待
语句WAIT UNTIL用于异步RFC调用中等待结果的返回,该项必须与PERFORMING附加项配合使用,否则没意义,也没效果。
WAIT UNTIL log_exp [UP TOsecSECONDS].
该语句执行时,log_exp中的条件将被检查。仅当条件满足时,调用程序继续执行,否则程序将挂起,并等待异步调用RFC调用的返回结果。
当功能模块调用结束时,系统将自动执行会掉子程序,在其中接受返回结果并设定相关的逻辑条件变量值,子程序结束后将回到WAIT UNTIL
语句。在多个异步调用存在的情况下,该等待过程将反反复复,直到等待条件被满足,或者不再有其他开放的异步rfc调用(如下图)。
注意:WAIT UNTIL语句将会重新设定sy-subrc.因此,如果在该语句后要用到RECEIVE RESULTS返回的sy-subrc值,就需要在离开回调子程序之前将其保存至一个全局变量.
3.事务性RFC
事务性RFC(tRFC)广义上也属于异步通信模式,调用程序不接收调用结果而继续运行,但并不立即启动远程功能。相关联的RFC可捆绑至一个事务(即逻辑工作单元LUW)中,然后通过事务性处理,将LUW内部各个调用中的更新操作作为整体提交或全部取消,且保证所有操作只执行一次,以确保RFC的可靠和安全。
在同步RFC和异步RFC过程中,每一个RFC调用都在远程系统中构成一个独立的LUW。通过事务性RFC调用,可以将多个逻辑上相关的远程调用绑定至同一个LUW上。在该LUW内,所有调用都按其调用顺序、在目标系统的相同程序上下文中以单个事物的方式执行,即要么执行所有数据库操作,要么回滚(功能模块终止)来取消全部数据库更新操作,这样就保证了RFC调用过程的完整性和数据一致性。这就是事务性RFC调用中所实现的“事务性”。事务性RFC调用处理保证在程序到达COMMIT WORK语句时执行所有计划的更新,并保证事务性RFC调用仅运行一次。
事务性RFC调用的语法:
CALL FUNCTION rfm_name
IN BACKGROUND TASK
[DESTINATION dest]
[EXPORTING p1 = a1...]
[TABLES t1 = itab1...]
[EXCEPTIONS exc1 = e1]
或者
CALL FUNCTION rfm_name
IN BACKGROUND UNIT oref
[DESTINATION dest]
[EXPORTING p1 = a1...]
[TABLES t1 = itab1...]
[EXCEPTIONS exc1 = e1]
在CALL FUNCTION语句中,通过在DESTINATION子句之前添加附加项IN BACKGROUND TASK或IN BACKGROUND UNIT,指明该调用为事务性RFC。在一个或多个事务性RFC调用之后,通过COMMIT WORK语句,就可以在一个LUW中完成之前的所有事务性RFC处理。在相邻两个COMMIT WORK之间出现的所有相同目标的异步调用都属于同一个LUW.
与异步调用类似,事务性RFC调用时不需要等待每个单独的更新过程完成,调用程序就可以立即继续进行,直至事物结束。但不同之处在于,事务性RFC调用中,远程RFC服务器在调用时不要求立即可用。如果调用发送时,远程系统不可用,调用将暂时保存在本地调用队列中。如果在设定时间内,RFC服务器仍不可用的话,调用将被设为后台作业运行。此外,事务性RFC不能从调用模块接受返回结果,且不允许调用者进行与远程系统的交互性对话及调试。这是事务性RFC调用与前两种RFC调用的一些不同之处。
队列RFC(qRFC)是事务性RFC功能上的进一步扩展。在事务性RFC中,存在多个LUW时,这些LUW的执行次序是无法确定的。如果要确保各个LUW都按照指定的顺序执行,可以通过队列RFC对事务性RFC进行序列优化。
1.调用参数
事务性RFC调用不能直接接收或通过RECEIVE RESULTS FROM FUNCTION 语句接收RFM的返回结果。因此,功能模块的接口中不应指定任何Export类型参数,否则该功能就不能通过事务性机制调用。
语法:
CALL FUNCTION 'TRAVEL_BOOK_REMOTE'
IN BACKGROUND TASK
DESTINATION 'GSE'
EXPORTING FLIGHT = sflight
CUSTMERID = customer.
...
COMMIT WORK.
...
系统将一直等待,直到到达COMMIT WORK语句,才开始与远程系统进行联系,并在此时进行全部已计划的远程数据库操作。
2.事务ID
每一个事务性RFC调用均通过一个独特的事务ID,存储于本地数据表ARFCSSTATE和ARFCSDATA中,其中表ARFCSSTATE记录LUW的执行状态,ARFCSDATA则包含事务性RFC调用的输入数据。调用程序执行到COMMIT WORK语句时,将为远程LUW计划一个立即或延迟开始的后台作业,并将远程调用转发给目标系统执行。作业执行过程中,从事务性RFC表中读取相关数据,与相应的事务性RFC进行通信。如果远程的LUW被成功执行,则相应的条目在表中删除。因此,如果LUW运行成功,则无法重新执行因而保证了仅仅执行一次。
3.检查事务性RFC调用的状态
(通过ABAP程序)
首先,TID可通过调用功能模块ID_OF_BACKGROUNDTASK在程序时确定。在CALL ... IN BACKGROUND TASK 之后和COMMIT WORK之前调用此功能模块,即可返回该LUW的TID。获得LUW的TID之后,就可以以继续使用功能模块STATUS_OF_BACKGROUNDTASK确定事务性RFC的状态了。
...
CALL FUNCTION 'TRACEL_BOOK_REMOTE'
IN BACKGROUND TASK
DESTINATION 'GSE'
EXPORTING
FLIGHT = sflight
CUSTOMERID = customer.
...
CALL FUNCTION 'ID_OF_BACKGROUNDTASK'
EXPORTING
TID = tid
IMPORTING
ERRORTAB = errtab
EXCEPTIONS
...
COMMIT WORK.
...
4.队列RFC
队列RFC(qRFC)是事务性RFC功能上的进一步扩展。在事务性RFC中,存在多个LUW时,这些LUW的执行次序是无法确定的。如果要确保各个LUW都按照指定的顺序执行,可以通过队列RFC对事务性RFC进行序列优化。
在事务性RFC调用中,如果COMMIT WORK语句提交多个LUW,那么各LUW之间相互独立。也就是说,其处理顺序并不取决于创建顺序。要确保事务性RFC调用中的LUW都按照其创建的次序执行,需要使用队列RFC创建LUW序列。
在编程方面,需要在普通事务性RFC调用之前使用功能模块TRF_SET_QUEUE_NAME来指明后续的事务性RFC所要插入的出站队列。
入站队列的指定则通过调用功能模块TRFC_SET_QTN_PROPERTIES来完成。
5.并行RFC
并行RFC(pRFC)实质上为异步RFC,在功能上实现多个SAP系统或同一SAP系统内部不同应用服务器间,以及应用服务器内部各个工作过程的并行处理。
5.1并行处理情况
在下述三种情况下,异步RFC调用本身可以实现并行处理:
(1)首先,异步RFC调用适用于多个SAP ABAP系统间的并行处理(不支持SAP系统和其他系统之间的并行过程。)
(2)此外,还可以在同一个SAP系统内部使用异步RFC调用,以将部分处理负载转移到其他的应用服务器。(同一个系统不同应用服务器)
(3)同一个应用服务器中工作过程的并行RFC过程。
同一SAP系统内部进行分组并行处理的语法格式如下:
CALL FUNCTION rfm_name
STARTING NEW TASK taskname
DESTINATION IN GROUP g1...
[EXPORTING p1 = a1...]
[TABLES t1 = itab1...]
[EXCEPTIONS exc1 = e1]
5.2并行处理前提条件
1.逻辑独立的工作单元
并行处理并不适合需要顺序进行的数据处理。前一个数据元素处理结束时下一个数据元素处理过程开始的前提条件,这就是典型的顺序处理过程。
并行的数据处理任务必须逻辑上独立于其他的任务实例,即任务的处理过程中既不共用其他并行处理过程的数据集,又不依赖于其他并行操作的执行结果。各个数据处理过程不能具有依赖关系。
2.ABAP要求
功能模块必须设定为远程支持,此外还需要满足:
(1)被调用的功能模块程序中不能再包含使用目标BACK的远程功能调用。
(2)调用程序不能在异步调用之后生成新的内部会话,即不能在CALL FUNCTION STARTING NEW TASK 语句后使用SUBMIT或CALL TRANSACTION语句。
(3)不能通过CALL FUNCTION STARTING NEW TASK DESTINATION IN GROUP 语句启动外部程序。
实例代码:
REPORT z_will_test MESSAGE-ID zpp.
*&------------------- PRFC(并行調用) ----------------------&*
TYPES: BEGIN OF task_type,
name TYPE string,
dest TYPE string,
END OF task_type.
DATA: snd_jobs TYPE i,
rcv_jobs TYPE i,
exc_flag TYPE i,
info TYPE rfcsi,
mess(90) TYPE c,
index(4) TYPE c,
name(8) TYPE c,
task_list TYPE STANDARD TABLE OF task_type,
task_wa TYPE task_type.
DO 10 TIMES.
index = sy-index.
CONCATENATE 'Task' index INTO name.
CALL FUNCTION 'RFC_SYSTEM_INFO'
STARTING NEW TASK name
DESTINATION IN GROUP DEFAULT
PERFORMING rfc_info ON END OF TASK
EXCEPTIONS
system_failure = 1
communication_failure = 2
RESOURCE_FAILURE = 3.
CASE sy-subrc.
WHEN 0.
snd_jobs = snd_jobs + 1.
WHEN 1 OR 2.
MESSAGE s999 WITH mess.
WHEN 3.
IF snd_jobs >= 1 AND
exc_flag = 0.
exc_flag = 1.
WAIT UNTIL rcv_jobs >= snd_jobs
UP TO 5 SECONDS.
ENDIF.
IF sy-subrc = 0.
exc_flag = 0.
ELSE.
MESSAGE s999 WITH 'Resource failure' INTO mess.
ENDIF.
WHEN OTHERS.
MESSAGE s999 WITH 'Other error' INTO mess.
ENDCASE.
ENDDO.
WAIT UNTIL rcv_jobs >= snd_jobs.
LOOP AT task_list INTO task_wa.
WRITE: / task_wa-name, task_wa-dest.
ENDLOOP.
*---------------------------------------------------------------------*
* FORM rfc_info *
*---------------------------------------------------------------------*
* ........ *
*---------------------------------------------------------------------*
* --> NAME *
*---------------------------------------------------------------------*
FORM rfc_info USING name.
task_wa-name = name.
rcv_jobs = rcv_jobs + 1.
RECEIVE RESULTS FROM FUNCTION 'RFC_SYSTEM_INFO'
IMPORTING
rfcsi_export = info
EXCEPTIONS
system_failure = 1
communication_failure = 2.
IF sy-subrc = 0.
task_wa-dest = info-rfcdest.
ELSE.
task_wa-dest = mess.
ENDIF.
APPEND task_wa TO task_list.
ENDFORM.
*&------------------- PRFC(并行調用) ----------------------&*