锁模式
模式E:当更改数据的时候设置为此模式。
模式S:本身不需要更改数据,但是希望显示的数据不被别人更改。
模式X:和E类似,但是不允许累加,完全独占。
多线程
并行RFC(负载均衡)
注意事项
并行RFC调用实际上是异步RFC调用的应用之一
异步RFC调用只适用于多个SAP ABAP系统间的并行处理,不支持SAP系统和其他系统之间
独立的LUW:并行处理不适合需顺序进行的数据处理,并行的数据处理任务必须逻辑上独立于其他任务,各个数据处理过程不能具有依赖关系
被调用的功能模块程序中不能再包含使用目标BACK的远程功能调用(即不能再进行回调)
调用程序不能在异步调用之后生成新的内部会话,即不能在CALL FUNCTION STARTING NEW TASK语句后使用SUBMIT或CALL TRANSACTION语句
不能通过CALL FUNCTION STARTING NEW TASK DESTINATION IN GROUP语句启动外部程序
异步实例
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(80),
indx(4),
name(8),
task_list TYPE STANDARD TABLE OF task_type,
task_wa TYPE task_type.
DO 9 TIMES.
indx = sy-index.
CONCATENATE 'Task' indx 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 MESSAGE mess
communication_failure = 2 MESSAGE mess
resource_failure = 3 .
CASE sy-subrc.
WHEN 1 OR 2.
MESSAGE mess TYPE 'I'.
WHEN 3.
MESSAGE 'Resource failure ' TYPE 'I'.
ENDCASE.
ENDDO.
WAIT UNTIL rcv_jobs = 9 UP TO 10 SECONDS.
LOOP AT task_list INTO task_wa.
WRITE: / task_wa-name,task_wa-dest.
ENDLOOP.
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 MESSAGE mess
communication_failure = 2 MESSAGE mess.
IF sy-subrc = 0.
task_wa-dest = info-rfcdest.
ELSE.
task_wa-dest = mess.
ENDIF.
APPEND task_wa TO task_list.
ENDFORM.
上面的程序有问题就是当发生RESOURCE_FAILURE会丢失数据。
需要使用子程序包装递归调用,递归调用前需要wait进程释放,否则程序一致循环,可能会占用太多系统内存,甚至产生system_no_menory错误代码如下。
*&---------------------------------------------------------------------*
*& Report ZTEST_YB_DEMO01
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT ztest_yb_demo01.
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,
ls_time TYPE i,
info TYPE rfcsi,
mess TYPE c LENGTH 80,
indx TYPE c LENGTH 4,
name TYPE c LENGTH 8,
task_list TYPE STANDARD TABLE OF task_type,
task_wa TYPE task_type.
*GET TIME STAMP FIELD DATA(ls_stamp).
DATA:g_taskname(10) TYPE c, "task name(同时运行的任务名称必须保持唯一)
g_classname TYPE rzlli_apcl, "Server Group Name
g_applserver TYPE rzllitab-applserver, "RFC Serve Group
lv_available TYPE i,
lv_total TYPE i,
lv_job TYPE i.
CALL 'C_SAPGPARAM' "#EC CI_CCALL
ID 'NAME' FIELD 'rdisp/myname'
ID 'VALUE' FIELD g_applserver.
SELECT SINGLE classname
FROM rzllitab
INTO g_classname "Server Group Name
WHERE applserver = g_applserver
AND grouptype = 'S'. "S:服务器组,空:登陆组
* 获取 RFC Serve Group name End--*
CALL FUNCTION 'SPBT_INITIALIZE'
EXPORTING
group_name = g_classname
IMPORTING
max_pbt_wps = lv_total
free_pbt_wps = lv_available
EXCEPTIONS
invalid_group_name = 1
internal_error = 2
pbt_env_already_initialized = 3
currently_no_resources_avail = 4
no_pbt_resources_found = 5
cant_init_different_pbt_groups = 6
OTHERS = 7.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
GET RUN TIME FIELD ls_time.
DO 200 TIMES.
indx = sy-index.
CONCATENATE 'Task' indx INTO name.
PERFORM frm_parallel_task USING name.
ENDDO.
WAIT UNTIL rcv_jobs GE snd_jobs .
*GET TIME STAMP FIELD DATA(ls_stamp1).
GET RUN TIME FIELD ls_time.
ls_time = ls_time / 1000000.
WRITE:/ `运行时间` && ls_time.
LOOP AT task_list INTO task_wa.
WRITE: / task_wa-name, ', Server:', task_wa-dest.
ENDLOOP.
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 MESSAGE mess
communication_failure = 2 MESSAGE mess.
IF sy-subrc = 0.
task_wa-dest = info-rfcdest.
ELSE.
task_wa-dest = mess.
ENDIF.
APPEND task_wa TO task_list.
CLEAR task_wa.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form FRM_PARALLEL_TASK
*&---------------------------------------------------------------------*
*& text
*&---------------------------------------------------------------------*
* -->P_NAME text
*&---------------------------------------------------------------------*
FORM frm_parallel_task USING p_name.
CALL FUNCTION 'RFC_SYSTEM_INFO'
STARTING NEW TASK name
* DESTINATION IN GROUP DEFAULT "g_classname "' 390' "pRFC
DESTINATION 'NONE'
PERFORMING rfc_info ON END OF TASK
EXCEPTIONS
system_failure = 1 MESSAGE mess
communication_failure = 2 MESSAGE mess
resource_failure = 3.
CASE sy-subrc.
WHEN 0.
* WAIT UP TO 1 SECONDS.
snd_jobs = snd_jobs + 1.
WHEN 1 OR 2.
MESSAGE mess TYPE 'I'.
WHEN 3.
WAIT UP TO '0.1' SECONDS.
PERFORM frm_parallel_task USING p_name.
WHEN OTHERS.
MESSAGE 'Other error' TYPE 'I'.
RETURN.
ENDCASE.
ENDFORM.
来自引用
1、DIALOG程序获得用户要更新的数据,并把它写到一个特殊的LOG TABLE,表内的条目属于同一个请求类型,包含了稍后将要写到数据库的数据。一个DIALOG程序可以写多条数据到LOG TABLE。写进LOG TABLE里的条目属于同一个LUW,意思就是它们要么都被执行,要么都不被执行。
2、DIALOG程序关闭LUW(将LOG TABLE的条目打包),并通知系统基本程序有一个包的数据需要更新。
3、系统基本程序从LOG TABLE读取这个LUW的需要更新的数据,并把这些数据提供给系统更新程序。
4、系统更新程序接受传输给它的数据,并更新数据库。
5、如果更新程序运行成功,系统基本程序删除这个LUW在LOG TABLE的所有数据;如果失败,保持LOG TABLE的这些数据,并标记不成功。触发更新程序的用户会收到系统发的关于这个错误的E-MAIL。可以用参数rdisp/vbmail(1发,0不发)来控制错误时是否发E-MAIL和rdisp/vb_mail_user_list($ACTUSER代表创建更新数据的用户)来控制错误时发E-MAIL给谁。可以用事务SM13来监控更新请求。
在DIALOG程序中,通过一个特别的FM,使用IN UPDATE TASK。如:
CALL FUNCTON 'F1' IN UPDATE TASK
EXPORTING
P1 = A
P2 = B.
使用这样写法的FM不会立即执行,而是写进LOG TABLE,作为一个执行请求,一个SAP LUW下的更新请求存储在同一个UPDATE KEY下。对一个SAP LUW来说UPDATE KEY是一个唯一的世界范围的识别码,意思就是一个SAP LUW的UPDATE KEY是唯一的,不会和另外的SAP LUW的UPDATE KEY重复。
只有当程序执行到COMMIT WORK的时候,才会为这些请求创建一个抬头条目LOG HEADER,表示以上这些同样UPDATE KEY的属于同一个包,然后系统关闭这个LUW。当LOG HEADER创建以后,系统通知DISPATCHER有一个更新包已经准备好可以处理了。
网友评论