【SAP Abap】X-DOC:SE37 - ABAP 功能模块之更新模块(Function Module 之 Update module)

1、简介

1.1、什么是更新函数

在SE37中,创建的功能模块,勾选了处理类型为“更新模块”后,即为更新函数。
在这里插入图片描述
SAP 的 Update Module 函数(又称为更新函数),主要用于对话或报表程序中实现同步或异步更新数据库的功能。对于需要更新数据库,但又对主程序的运行不产生影响(即更新成功与否不影响主程序的正常执行)的操作,可以使用更新任务(即Update Module函数的IN UPDATE TASK)来实现。更新模块在程序中使用 CALL FUNCTION IN UPDATE TASK 调用,此时函数并不会立即执行,而是在执行到COMMIT WORK 时才会触发执行。

典型的SAP 系统配置包括对话任务和更新任务,对话任务处理与用户的交互会话,更新任务专用于执行数据库更新。更新函数用于在对话任务和更新任务中执行更新,对话任务更新是同步更新,更新任务更新是异步更新(例外:用 COMMIT WORK AND WAIT 触发更新任务功能时,它是同步更新)。

在事务内部,对于每条 COMMIT WORK 语句可以调用一个或多个更新任务功能模块。在报表中,也可以通过 COMMIT WORK 语句显式提交更新任务功能模块。更新函数只能在 COMMIT WORK 或 ROLLBACK WORK 处才会被执行,一般调用事务内部,在完成一个 SAP LUW时都有一个隐式的 COMMIT WORK 功能,故不用再明确提交;而在报表事务中,需要显式使用 COMMIT WORK 功能进行更新函数的提交。

1.2、更新函数的类型

更新函数分为V1和V2两类,决定了更新函数执行的先后顺序。只有当V1请求执行成功之后才会处理V2请求,所以V2类型的数据库更新操作一般都是紧接着V1类型的数据库更新操作之后进行的。V1 类型的 UPDATE MODULE 分可重新启动和不可重新启动两种。V2类型的当发生错误的时候总是可以重新启动,再次处理。

V1类型
(1)立即开始(可重启),在同一个 更新事务(SAP LUW)中运行的优先级为高,当出现错误时更新任务可以重新启动这些功能。
(2)立即启动(不可重启),在同一个更新事务(SAP LUW)中运行的优先级为高,但不能由更新任务重新启动这些功能。
V2类型
(1)延迟启动(可重启),在同一个更新事务(SAP LUW)中运行的优先级为低,当出现错误时更新任务可以重新启动这些功能。
(2)集中运行(collective run),SAP内部使用,该类型的V2请求并不会直接执行,而需要在程序 RSM13005 被调用之后才执行。

1.3、更新函数的参数要求

(1)可用参数类型
因为更新任务功能模块不能报告其结果,因此不允许有结果参数(EXPORTING,CHANGING),只能有输入参数(IMPORTING)和表参数(TABLES),以及例外(EXCEPTIONS)。如果创建传出参数(EXPORTING)和修改参数(CHANGING),程序将检查不通过。
(2)传入参数设置
在更新函数中传入参数(IMPORTING)只允许使用
值传递方式
,且必须指定参数类型,对应的参数须使用参照字段进行定义。
(3)传出参数设置
更新函数可以有TABLE参数,并且该表格需要有对应的参考结构。一般使用TABLE参数用于获取更新执行成功与否的反馈消息(RETURN表格);或者传入用于查询数据的参考内表(尽量不更改传入内表的数据)。
(4)源代码
UPDATE MODULE里包含实际的数据库更新语句。

1.4、更新函数的调用方式

将函数设置为更新模块后,调用时既可以将该函数定义到更新任务中,也可以作为普通函数进行调用。
(1)作为普通函数调用
使用普通函数的 CALL FUNCTION 的调用方式实现即可,此时该函数仅作为普通函数执行,不作为更新函数。

  CALL FUNCTION 'YFM_UPDATE_01_V1'
    EXPORTING
      iv_tag = '1、Normal FM'.

(2)作为更新函数调用
作为更新函数调用,则需要在普通函数的 CALL FUNCTION 调用语句上附加 IN UPDATE TASK,则更新函数将在一个 SAP LUW 执行到 COMMIT WORK 处时,系统统一执行。

  CALL FUNCTION 'YFM_UPDATE_01_V1' IN UPDATE TASK
    EXPORTING
      iv_tag    = '2、Update FM, By Import'.

1.5、更新函数的调试方式

三类函数的调试存在很大的区别。普通函数需要通过内部断点进行调试,RFC函数需要设置调试外部请求用户,通过外部断点进行调试。
更新函数需要更改调试器设置,开启“更新调试”模式(如果勾选’提交’按钮,只会在本次登录中有效。如果勾选’保存’按钮,下次登录后该调试功能依旧有效。),才能在程序处理完 COMMIT WORK 语句之后,自动进入更新函数调试界面。
在这里插入图片描述

1.6、更新任务的执行模式

(1)异步模式,不同进程(COMMIT WORK)
在这个模式下,对话程序会用一个 COMMIT WORK 来关闭 LUW,更新程序被 COMMIT 触发并开始运行来处理这些请求。此时对话程序和更新程序在各自的进程中运行,对话程序会继续运行,不会等待更新程序结束。
当数据库更新花费比较长的时间,用户对话需要较少的响应时间,异步更新显得比较重要。在对话处理中,异步更新是标准的方式,对话程序一般会采取异步更新方式。

(2)同步模式,不同进程(COMMIT WORK AND WAIT)
可以用 COMMIT WORK AND WAIT 语句来触发一个同步更新,对话程序会等待更新程序结束再进行下一步的处理。对于同步更新,可以使用SY-SUBRC来检查同步更新的执行情况,在程序等待更新程序执行的过程中,对话程序的 DIALOG WORK PROCESS 被释放,当更新结束之后,系统重新为对话程序分配一个新的空闲的 DIALOG WORK PROCESS 做下一步的处理。
如果后续处理或者对话程序的结束需要依靠更新的结果,这个时候要用同步模式。

(3)本地模式,同一进程(SET UPDATE TASK LOCAL)
使用 SET UPDATE TASK LOCAL 语句来使 UPDATE MODULE 在本地执行,同样的用 COMMIT WORK 来关闭 SAP LUW,不管 COMMIT是否 WAIT,更新会在同一个 DIALOG WORK PROCESS 中进行(即同一个SAP LUW),对话程序等待更新完成。当LOCAL UPDATE完成之后,会提交一个 DB COMMIT,对话程序也得以继续执行;如果更新执行有错误,并且其中一个 UPDATE MODULE 发出一个终止程序的消息(通知到请求用户),系统会执行一个自动的DB ROLLBACK来丢弃这个SAP LUW所有的改变,并且对话程序会终止,并弹出一个程序终止信息。
LOCAL UPDATE模式中,更新请求不会写到VBLOG表中,而是在MAIN MEMORY中,因为没有IO的访问,其速度要比同步和异步模式的快一点。LOCAL UPDATE只适合批量模式。
注:
① SET UPDATE TASK LOCAL只对一个LUW起作用,且必须在第一个update task注册之前申明,即如果多次调用COMMIT,就需要每次都在第一个update task之前申明SET UPDATE TASK LOCAL。
② 本地更新模式仅对V1类型请求起作用,V1请求将在MAIN MEMORY中创建的,V2类型的请求总是创建到LOG表中。

1.7 更新任务的执行过程

(1)DIALOG 程序获得用户要更新的数据,并把更新任务写到一个特殊的LOG表,表内的条目属于同一个请求类型,包含了稍后将要写到数据库的数据。一个 DIALOG 程序可以写多条数据到LOG表,写进LOG表里的条目属于同一个LUW。一个 SAP LUW 下的更新请求存储在同一个 UPDATE KEY 下,只有当程序执行到 COMMIT WORK 的时候,才会为这些请求创建一个抬头条目LOG HEADER,表示以上这些同样 UPDATE KEY 的属于同一个包,它们要么都被执行,要么都不被执行。
(2)DIALOG 程序通过 COMMIT 关闭 LUW(将LOG表的条目打包),并通知系统基本程序有一个包的数据需要更新。
(3)系统基本程序从LOG 表读取这个 LUW 的需要更新的数据,并把这些数据提供给系统更新程序。
(4)系统更新程序接受传输给它的数据,并更新数据库。
(5)如果更新程序运行成功,系统基本程序删除这个LUW在LOG表的所有数据;如果失败,保持LOG表的这些数据,并标记不成功。同时触发更新程序的用户会收到系统发的关于这个错误的消息。可以用SM13来检查LOG条目。

注:
(1)LOG表,ECC使用VBLOG这个簇表来实现,S4使用透明表VBHDR、VBMOD、VBDATA、VBERROR 来替代它,前端查看更新任务状态使用事务码 SM13。
(2)可以用参数rdisp/vbmail(1发,0不发)来控制错误时是否发E-MAIL和rdisp/vb_mail_user_list($ACTUSER代表创建更新数据的用户)来控制错误时发E-MAIL给谁。
(3)当丢弃当前SAP LUW的所有changes(比如结束TCODE),可以使用ROLLBACK WORK或者弹出一个A类型的MESSAGE,这两个语句都可以有以下的效果:
-删除写到该点之前的所有的change requests
-删除写到该点之前所有的锁
-丢弃当前DB LUW执行的changes
-丢弃所有使用POC形式登记的subroutines
(4)DIALOG 程序用_SCOPE = 2创建的锁会被传递到V1 更新任务中,在V1更新的结束,不管V1更新是否成功或者终止,都会把这些锁自动删除。因此,在DIALOG程序中不能显式的删除这些锁(太早),或者在UPDATE MODULE里删除(没必要)。

1.8、更新任务的执行监控

使用事务码 SM13 ,可以监控更新请求。
在这里插入图片描述
点击执行后存在两个更新任务。
在这里插入图片描述
第一行的STATUS为INITIAL表明程序还未执行(一般调试模式才可见);
第二行的STATUS为红色,表明程序执行过程有错误,可以点击进入更新函数列表。
在这里插入图片描述其中包含四个更新函数,分别为V2、V1类型:
根据V1,V2类型的区别(优先执行V1,待全部执行后再执行V2)。
程序首先执行V1类型的更新函数,V1函数执行成功后,更新函数列表如图所示,状态显示“已处理”,程序继续执行V2类型的更新函数;若V1类型的更新函数执行出错,则不再继续执行后续任务,直接进行更新事务回滚,同时标记更新任务列表中该记录为出错。
V2类型更新函数执行过程类似,若执行出错,则回滚V2类型的更新事务,同时标记该记录为出错;若全部执行成功,则在更新任务列表中该记录消失。
更新任务发生错误时,会向任务请求者发送一条消息提醒。
针对存在错误的更新函数,我们可通过点击更新任务列表详细查看报错的函数。
双击弹出提示框,可点击ABAP SHORT DUMP按钮查看详细报错信息。同样我们也可通过ST22查看报错记录。

1.8、注意事项

(1)在update task里不能使用commit work / rollback,否则会dump,尽量不要使用check, 避免检查失败不运行其他业务逻辑。
(2)使用update task可以控制出错时多个update module同时回滚。
(3)在update module中打断点是不会进去的,dump了也不会报出来,会把错误发到用户的收件箱。

2 、应用

更新函数的使用范围是很广泛,尤其在ERP与其他系统的接口功能设计时使用很方便。

2.1、执行顺序的应用

在功能封装中,对于系统表的增强字段更新,或是获取系统表的字段值,可以在系统BAPI或更新函数执行后增加一个V2类型的更新函数,因为系统先执行其自带的V1和V2类型的更新函数,然后再执行自定义的V2类型的更新函数,可以在同步模式WAIT后,实现对透明表的直接操作。

2.2、更新事务的应用

在ABAP的开发中,根据业务的需要,同时对后台多个数据表进行更新,为了保证数据的完整性、一致性,需要把这些操作写在同一个更新事务中,实现对数据的操作,要么全部成功,要么全部失败回滚。
又如自动过账程序,将过账的更新和对自定义表的更新操作,用一个更新模块来封装,通过这种方式确保操作都在更新进程中执行, 如果过账更新报错,会中断更新过程,自定义表也就不会更新了。

2.3、隐式增强的应用

在单据保存类增强项,可以在隐式增强中调用自建更新函数的方式来实现。

2.4、应用更新进程机制

尽量使用 IN UPATE TASK 提交自定义表的更新,应用系统的更新进程机制,如果存在更新错误,可以通过SM13查看报错的信息。

3、示例

3.0、系统应用案例

SAP 系统中,一些单据保存到数据库用的是 update mudule function。
命名是ME_UPDATE_* (业务说明)
例:
ME_UPDATE_REQUISITION PR save module
ME_UPDATE_INFORECORD 更新采购主记录数据
ME_UPDATE_AGREEMENT_PO 更新采购凭证
ME_UPDATE_SCHEDULE_EKPO 计划协议下达
ME_UPDATE_DELIVERY 更新采购凭证

3.1、测试用表及函数

(1)测试用表
在这里插入图片描述
(2)测试用函数
① YFM_UPDATE_01_V1
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
② YFM_UPDATE_02_V1
在这里插入图片描述
③ YFM_UPDATE_03_V2
在这里插入图片描述
④ YFM_UPDATE_04_V2
在这里插入图片描述

FUNCTION yfm_update_01_v1.
*"----------------------------------------------------------------------
*"*"更新函数模块:
*"
*"*"本地接口:
*"  IMPORTING
*"     VALUE(IV_A) TYPE  INT2 OPTIONAL
*"     VALUE(IV_B) TYPE  INT2 OPTIONAL
*"     VALUE(IV_OP) TYPE  CHAR1 OPTIONAL
*"     VALUE(IV_TAG) TYPE  YEF5 OPTIONAL
*"     VALUE(IV_ERRORX) TYPE  CHAR1 OPTIONAL
*"     VALUE(IV_SEC) TYPE  I DEFAULT 0
*"  TABLES
*"      IT_DATA STRUCTURE  YTTEST OPTIONAL
*"      ET_DATA STRUCTURE  ZSBC003 OPTIONAL
*"  EXCEPTIONS
*"      ON_ZERO
*"----------------------------------------------------------------------

  DATA: lv_fm_name TYPE string VALUE 'V1-01'.
  WAIT UP TO iv_sec SECONDS.    "<---- a database commit is triggered (except during updates).
  DATA ls_yttest TYPE yttest.
  IF iv_errorx EQ 'X'.
    ls_yttest = it_data[ 0 ].   " Trrigger A Dump
  ENDIF.

  DATA p_no type yeitemo.
  PERFORM get_no CHANGING p_no.

  IF it_data[] IS NOT INITIAL.
    ls_yttest = VALUE #( it_data[ 1 ] OPTIONAL ).
    ls_yttest-itemo = p_no.
    ls_yttest-yf4 = lv_fm_name.
    ls_yttest-ydatetime = |{
    
     sy-datum }{
    
     sy-uzeit }|.
  ELSE.
    GET TIME STAMP FIELD DATA(lv_timestamp).
    ls_yttest = VALUE yttest(
      itemo = p_no
      yf1 = iv_a
      yf2 = iv_b
      yf3 = iv_op
      yf4 = lv_fm_name
      yf5 = iv_tag
      ydatetime = |{
    
     sy-datum }{
    
     sy-uzeit }|
    ).
  ENDIF.
  MODIFY yttest FROM ls_yttest.

ENDFUNCTION.

*&---SNRO取值编号
FORM get_no CHANGING p_no.
  CALL FUNCTION 'NUMBER_RANGE_ENQUEUE'
    EXPORTING
      object           = 'YITEMO'
    EXCEPTIONS
      foreign_lock     = 1
      object_not_found = 2
      system_failure   = 3
      OTHERS           = 4.
  IF sy-subrc = 0.                    "如果号码范围存在
    CALL FUNCTION 'NUMBER_GET_NEXT'   "将号码累加,获得下一个流水号
      EXPORTING
        nr_range_nr             = '01'
        object                  = 'YITEMO'
      IMPORTING
        number                  = p_no
      EXCEPTIONS
        interval_not_found      = 1
        number_range_not_intern = 2
        object_not_found        = 3
        quantity_is_0           = 4
        quantity_is_not_1       = 5
        interval_overflow       = 6
        buffer_overflow         = 7
        OTHERS                  = 8.
    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
         WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    ELSE.
      CALL FUNCTION 'NUMBER_RANGE_DEQUEUE'
        EXPORTING
          object           = 'YITEMO'
        EXCEPTIONS
          object_not_found = 1
          OTHERS           = 2.
    ENDIF.
  ENDIF.
ENDFORM.
FUNCTION yfm_update_02_v1.
  ...
  DATA: lv_fm_name TYPE string VALUE 'V1-02'.
  ...
ENDFUNCTION.
FUNCTION yfm_update_03_v2.
  ...
  DATA: lv_fm_name TYPE string VALUE 'V2-01'.
  ...
ENDFUNCTION.
FUNCTION yfm_update_04_v2.
  ...
  DATA: lv_fm_name TYPE string VALUE 'V2-02'.
  ...
ENDFUNCTION.

3.2、Demo1(同步、异步、本地)

*&---------------------------------------------------------------------*
*& Report YZ_DEMO_CALL_UPDATE_FM
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT yz_demo_call_update_fm.
INCLUDE yz_demo_call_update_fm_f01.

DATA: gv_tag TYPE char50.

START-OF-SELECTION.
  "clear test data
  DELETE FROM yttest.

  "call normal fm, value can pass by constant
  CALL FUNCTION 'YFM_UPDATE_01_V1'
    EXPORTING
      iv_tag = '1、Normal FM'.

  " update fm will be called after commit,in the same dialog work process
  " must put before the first update fm in one sap luw
*SET UPDATE TASK LOCAL.
  " call update fm by import, value must pass by parameter ??
  " execute after commit in a new update work process
  PERFORM frm_call_update_fm USING 'YFM_UPDATE_01_V1' '2、Update FM, By Import' ''.

  "local
  PERFORM frm_add_data USING '3、Local'.

*COMMIT WORK.             "<---- End SAP LUW and start a new one
  WAIT UP TO 1 SECONDS.     "<---- a database commit is triggered (except during updates).
  "No wait may lead to cannot get number for update task(2Update FM, By Import*SET UPDATE TASK LOCAL.    " update fm will be called after commit,in the same dialog work process
  "call update fm by tables
  DATA: lt_data TYPE TABLE OF yttest.
  lt_data = VALUE #( (
      yf5 = '4、Update FM, By Tables'
      )
    ).
  CALL FUNCTION 'YFM_UPDATE_01_V1' IN UPDATE TASK
    EXPORTING
      iv_errorx = ''     " trrigger error, if run in update work process, an email will be sent
    TABLES
      it_data   = lt_data.

  DO 2 TIMES.                         " only trrigger once
    gv_tag = '5、Local, on Commit'.
    PERFORM frm_mod_data ON COMMIT.   " execute in the same dialog work process and before updata module
  ENDDO.

  "local
  PERFORM frm_add_data USING '6、Local'.

  gv_tag = '5、Local, on Commit, changed before commit'.      " effect in form on commit
  COMMIT WORK AND WAIT.       "<---- End SAP LUW and start a new one
  " Note:
  " Implicit Commit cannot trrigger the update fm
  " Explicit Commit can trrigger the update fm
  "   commit work, asynchronous with new update work process
  "   commit work and wait, synchronous with new update work process
  "   set update task local, synchronous with same dialog work process

  "show test data
  SELECT * FROM yttest INTO TABLE @DATA(lt_yttest).
  cl_demo_output=>display( lt_yttest ).

FORM frm_mod_data.
  PERFORM frm_add_data USING gv_tag.
ENDFORM.

3.3、Demo2(V1、V2优先级)

*&---------------------------------------------------------------------*
*& Report YZ_DEMO_CALL_UPDATE_FM
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT yz_demo_call_update_fm2.
INCLUDE yz_demo_call_update_fm_f01.

START-OF-SELECTION.
  "clear test data
  DELETE FROM yttest.

  "call update
  PERFORM frm_call_update_fm USING 'YFM_UPDATE_04_V2' '1、Update FM(V2-2)' ''.

  PERFORM frm_call_update_fm USING 'YFM_UPDATE_03_V2' '2、Update FM(V2-1)' ''.

  PERFORM frm_call_update_fm USING 'YFM_UPDATE_02_V1' '3、Update FM(V1-2)' ''.

  PERFORM frm_call_update_fm USING 'YFM_UPDATE_01_V1' '4、Update FM(V1-1)' ''.

  "local
  PERFORM frm_add_data USING '5、Local'.

  COMMIT WORK AND WAIT.   "<---- End SAP LUW and trrigger the three updata fm
  WAIT UP TO 1 SECONDS.   " wait for the result of v2 update fm

  "show test data
  SELECT * FROM yttest INTO TABLE @DATA(lt_yttest).
  cl_demo_output=>display( lt_yttest ).

原创文章,转载请注明来源-X档案

猜你喜欢

转载自blog.csdn.net/XLevon/article/details/130663411