ABAP中如何在独立LUW更新单数据表?现有方案遇提交异常
问题背景
我需要在多个ABAP应用中实现错误日志记录功能,为此创建了日志表zdt_error_log,并通过工具类方法update_logging_table写入日志。为了不影响主程序的逻辑工作单元(LUW),我尝试用STARTING NEW TASK异步调用函数模块提交日志修改,期望只提交函数模块中的「Function Module」日志,主程序里的「Prog」日志由主程序自行控制提交时机。
但测试发现,调用该异步函数模块时,系统会立即自动执行COMMIT WORK,导致主程序中未提交的「Prog」日志被一并提交;而函数模块内的日志则在自身的COMMIT WORK后再次提交。我已经试过更新函数、后台任务、提交程序、PERFORM ON COMMIT等方案,均未解决问题。
相关代码
主程序代码
REPORT zak_test_luw. DATA: ls_log TYPE zdt_error_log, lv_tms TYPE timestampl. GET TIME STAMP FIELD lv_tms. ls_log-time_stamp = lv_tms. ls_log-msg1 = 'prog'. ls_log-msg2 = ''. MOVE-CORRESPONDING sy TO ls_log. MODIFY zdt_error_log FROM ls_log. zdcl_utility_new=>update_logging_table( iv_msg1 = |Function Module| ).
工具类方法代码
METHOD update_logging_table. DATA: ls_log TYPE zdt_error_log, lv_tms TYPE timestampl. GET TIME STAMP FIELD lv_tms. ls_log-time_stamp = lv_tms. ls_log-msg1 = iv_msg1. ls_log-msg2 = iv_msg2. MOVE-CORRESPONDING sy TO ls_log. IF commit_work = abap_true. MODIFY zdt_error_log FROM ls_log. COMMIT WORK. ELSE. CALL FUNCTION 'ZDF_UPDATE_ERROR_LOG_TBL' STARTING NEW TASK 'LOGTABLE ' EXPORTING is_log = ls_log. ENDIF. ENDMETHOD.
函数模块代码
FUNCTION zdf_update_error_log_tbl. *"---------------------------------------------------------------------- *"*"Local Interface: *" IMPORTING *" VALUE(IS_LOG) TYPE ZDT_ERROR_LOG *"---------------------------------------------------------------------- MODIFY zdt_error_log FROM is_log. COMMIT WORK. ENDFUNCTION.
问题原因
使用STARTING NEW TASK调用异步函数模块时,ABAP系统会隐式触发一次COMMIT WORK——这是因为异步任务运行在独立会话,无法访问当前会话的未提交数据,系统会先提交当前LUW的所有修改,确保异步任务能读取到一致的数据状态。这就导致主程序中未提交的「Prog」日志被意外提交。
解决方案
方案1:使用更新函数模块(推荐)
更新函数模块专门用于延迟提交,修改会被放入更新队列,直到主程序执行COMMIT WORK时统一处理。若需日志独立于主程序LUW提交,可搭配COMMIT WORK AND WAIT单独触发更新。
调整步骤:
- 修改函数模块属性:将
ZDF_UPDATE_ERROR_LOG_TBL标记为更新函数模块(SE37中勾选「Update Module」,类型选V1或V2) - 更新工具类方法代码:
METHOD update_logging_table. DATA: ls_log TYPE zdt_error_log, lv_tms TYPE timestampl. GET TIME STAMP FIELD lv_tms. ls_log-time_stamp = lv_tms. ls_log-msg1 = iv_msg1. ls_log-msg2 = iv_msg2. MOVE-CORRESPONDING sy TO ls_log. IF commit_work = abap_true. MODIFY zdt_error_log FROM ls_log. COMMIT WORK. ELSE. CALL FUNCTION 'ZDF_UPDATE_ERROR_LOG_TBL' IN UPDATE TASK EXPORTING is_log = ls_log. " 立即提交日志,不等待主程序COMMIT COMMIT WORK AND WAIT. ENDIF. ENDMETHOD.
- 移除函数模块内的
COMMIT WORK:
FUNCTION zdf_update_error_log_tbl. *"---------------------------------------------------------------------- *"*"Local Interface: *" IMPORTING *" VALUE(IS_LOG) TYPE ZDT_ERROR_LOG *"---------------------------------------------------------------------- *" 更新函数模块属性:勾选Update Module,类型V1/V2 *---------------------------------------------------------------------- MODIFY zdt_error_log FROM is_log. ENDFUNCTION.
方案2:使用后台作业提交日志
创建专门的日志写入程序,通过后台作业执行提交操作,完全隔离主程序LUW。
示例代码:
METHOD update_logging_table. DATA: ls_log TYPE zdt_error_log, lv_tms TYPE timestampl, lv_jobname TYPE tbtcjob-jobname VALUE 'LOG_SUBMIT_JOB', lv_jobcount TYPE tbtcjob-jobcount. GET TIME STAMP FIELD lv_tms. ls_log-time_stamp = lv_tms. ls_log-msg1 = iv_msg1. ls_log-msg2 = iv_msg2. MOVE-CORRESPONDING sy TO ls_log. IF commit_work = abap_true. MODIFY zdt_error_log FROM ls_log. COMMIT WORK. ELSE. CALL FUNCTION 'JOB_OPEN' EXPORTING jobname = lv_jobname IMPORTING jobcount = lv_jobcount EXCEPTIONS cant_create_job = 1 invalid_job_data = 2 jobname_missing = 3 OTHERS = 4. IF sy-subrc = 0. SUBMIT zak_log_writer WITH p_log = ls_log AND RETURN VIA JOB lv_jobname NUMBER lv_jobcount. CALL FUNCTION 'JOB_CLOSE' EXPORTING jobname = lv_jobname jobcount = lv_jobcount strtimmed = abap_true EXCEPTIONS cant_start_immediate = 1 invalid_startdate = 2 jobname_missing = 3 job_close_failed = 4 job_nosteps = 5 job_notex = 6 lock_failed = 7 OTHERS = 8. ENDIF. ENDIF. ENDMETHOD.
其中zak_log_writer是独立的日志写入程序,接收p_log参数并执行MODIFY和COMMIT WORK。
内容的提问来源于stack exchange,提问作者Arun Kamath

