背景:
在做ABAP開發時,經常會有連續調用BAPI的需求,比如先創建銷售訂單,再依據銷售訂單創建交貨單,再對交貨單進行過賬等類似的一連串調用,這種類似的場景往往需要前一步操作的數據完全寫入數據庫才能進行一下個步驟,但是數據寫入底表是需要時間的,如果一些業務數據比較復雜,可能在調用下一個BAPI時會因為數據尚未寫入底表而導致BAPI報出單據不存在等類似的錯誤消息(如果BAPI是以異步提交方式處理),這時候不同的開發者會往往有不同的處理方式,比如WAIT UP TO XXX SECONDS之類的操作,但并不推薦這么去做,因為往往會浪費一些不必要的時間,本文將結合筆者自身經驗來分析這個問題,提供一些不同的解決方式,根據實際情況進行選擇。
BAPI的執行原理:
大部分BAPI執行的大概過程如下:
①:報表程序中調用BAPI;
②③④:BAPI內部經過一系列檢查處理后,將需要更新提交的數據統一注冊到更新進程LUW中;
如果BAPI本身比較規范的話,一般會有類似COMMIT_WORK以及COMMIT_WORK_AND_WAIT等類似的傳入參數,那么我們最好是通過參數使其內部以同步方式⑤提交,或者使其內部不要提交,由調用者來決定是否已同步方式⑥提交(AND WAIT附加項決定了更新進程是否以同步模式提交);
在碰到COMMIT WORK語句后,之前注冊的所有更新函數將按照順序依次執行⑦⑧⑨⑩,并且BAPI中產生的鎖會一并帶到更新進程中,優先執行V1更新,V1更新執行完畢后,數據庫進行提交,并且釋放所有的鎖,V2進程不會再有加鎖的操作,V2執行完畢后,整個數據庫提交過程完畢,如果更新進程中出錯,則會自動觸發回滾,并收到一條Dump快件;
如果是以同步提交(COMMIT WORK AND WAIT)觸發更新,則程序會在更新進程執行完畢后才返回至調用程序⑩,如果是以異步方式(COMMIT WORK)觸發更新,則程序不會等待更新進程執行完畢,立即進行后續處理⑩,這種時候如果要對該BAPI產生的單據進行下一步處理,則可能會出現單據不存在,或者鎖定報錯;
某些BAPI中的更新進程中甚至會有上圖中⑨的處理流程,將一部分數據處理用IN BACKGROUD TASK的方式去觸發異步事務性函數(tRFC)處理,盡管這種方式已被SAP標記為過時的方式,但是仍然有一些BAPI中采用了這種方式,比如報工BAPI:BAPI_PRODORDCONF_CREATE_TT,其中針對于貨物移動的處理就是采用的這種方式,使用IN BACKGROUND TASK觸發的事務會立即以異步方式在獨立進程中執行,所以AND WAIT不會對其生效。
更新進程的處理流程:
官方說明:
After the transaction closes, the dialog work process closes the VBHDR entry (the beginning of the update for the?update request), and searches for an update server for the U1 update. This described in more detail in?Update Dispatching with Load-Balancing.
The update server distributes the tasks to an update work process. This processes the V1 modules of the update request, triggers a COMMIT to the database, and releases the R/3 locks on the update request (see?The SAP Lock Concept). Then the work process searches for an update server for the U2 update, if the U2 update modules exist.
These are forwarded from a U2 update server to a U2 work process that processes the U2 modules, and triggers a COMMIT on the database.
The following graphic displays this process from the view of various work processes. It also displays the time at which changes to the database are made.
官方說明:
The U1 modules are processed by transmitting the contents of the update table VBMOD and VBDATA to the application tables of the database. The changes are actually in the desired tables in the database only at the end of the database LUW in which it occurs. The SAP locks are released and, if?V2?update modules exist, the?V2?update is started. This is similar to the V1 update with the exception that there are no locks that have to released and no search for a process for further processing.
需要注意的是,V1更新是可選同步更新或者異步更新,根據附加項AND WAIT來決定,V2更新則永遠是異步更新,COMMIT WORK AND WAIT也只會等待V1更新完畢。?
COMMIT WORK AND WAIT不生效的原因:
知道了BAPI以及更新進程的原理,那同步提交不生效的原因就變得清晰了,大概有以下幾種情況:
- BAPI沒有NO_COMMIT以及COMMIT_WORK_AND_WAIT等類似的參數,直接在內部執行了COMMIT WORK語句(沒有附加AND WAIT),因為內部的COMMIT WORK已經觸發了更新進程的處理,所以調用程序中的COMMIT WORK AND WAIT將沒有東西可觸發,所以會不生效,類似的BAPI有BAPI_MATERIAL_SAVEDATA,BAPI_ENTRYSHEET_CREATE 和 BAPI_PO_RESET_RELEASE等。
- BAPI本身提供了NO_COMMIT參數,但是調用時未傳入該參數,導致BAPI內部仍然以異步方式進行了提交,故調用側的同步提交不生效,類似的BAPI有BAPI_PO_RELEASE,CO_SE_PRODORD_OPR_CREATE等。
- BAPI在更新進程中觸發了新的異步遠程更新進程,如報工BAPI:BAPI_PRODORDCONF_CREATE_TT,COMMIT WORK AND WAIT只會等到IN UPDATE TASK注冊的更新進程處理完畢,并不會等待IN BACKGROUND TASK注冊的更新進程。
標準BAPI事務模型規范:
BAPI 事務模型必須為用戶提供明確的事務控制權。因此,如果同時調用多個 BAPI,則調用方可以自行決定何時執行 COMMIT WORK(或者,視情況而定,執行 ROLLBACK WORK)。這意味著 BAPI 本身不能(通常)執行 COMMIT WORK 命令。
以下限制適用于將多個 BAPI 合并到一個 LUW 中:
- 如果實例是由寫入 BAPI 創建、修改或刪除的,則讀取 BAPI 只有在發生 COMMIT WORK 時才能訪問最新數據。
- 不能在一個 LUW 中的同一實例上進行兩次寫入訪問。例如,不能先在同一 LUW 中創建然后更改對象。但是,您可以在 LUW 中創建同一對象類型的多個實例。
盡管 SAP 提供的所有 BAPI 都應遵循此事務模型,但也有例外,并不是所有BAPI都會按照這個規范去操作,所以碰到這種情況,則需要按照實際情況去分析處理。
如何解決:
解決該問題的方式有很多種,其中最不推薦的則是WAIT UP TO XXX SECONDS的方式,盡管高版本中可以選擇WAIT UP TO '0.1' SECONDS的方式,但對于一些強迫癥開發者來說,多余浪費的0.01秒都是不能容忍的,所以可以有以下幾種替代方式來處理異步提交問題。
1:分組處理
比如針對一批數據的每一條,都需要調用完創建BAPI之后再調用修改BAPI對其修改,則可以先統一進行創建處理,再進行修改處理,通常當所有單據創建完之后,最先創建的單據應該早已提交更新完畢,示例如下:
改造前:
...
LOOP AT objects.CALL FUNCTION 'BAPI_OBJECT_CREATE'.CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'IMPORTINGWAIT = 'X'.CALL FUNCTION 'BAPI_OBJECT_CHANGE'.CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'IMPORTINGWAIT = ' '.ENDIF.
ENDLOOP.
改造后:
...
LOOP AT objects.CALL FUNCTION 'BAPI_OBJECT_CREATE'.CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'IMPORTINGWAIT = ' '.
ENDLOOP.
LOOP AT objects.IF object not exists.APPEND object TO object_work_listELSE.CALL FUNCTION 'BAPI_OBJECT_CHANGE'.CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'IMPORTINGWAIT = ' '.ENDIF.
ENDLOOP.
Reprocess the objects in object_work_list and wait
2:SET UPDATE LOCAL TASK
SET UPDATE LOCAL TASK會忽略IN UPDATE TASK附加項,使BAPI中數據庫更新的過程以本地更新的方式在當前會話內部單獨執行,而非注冊到VB更新進程中,并且COMMIT WORK會隱式的添加同步提交,但每次COMMIT WORK之后,本地更新會被禁用,所以需要的時候需要在每次調用BAPI之前執行SET UPDATE LOCAL TASK語句來開啟本地更新,該方式適用于數據庫提交函數中沒有觸發異步遠程RFC的BAPI,例如BAPI_PRODORDCONF_CREATE_TT。
3:使用時間戳+WHILE
通過下面的代碼,可以將等待時間減少到盡可能短的等待時間 ,具體取決于使用情況,從而不會浪費額外多余的時間。
DATA: BEGIN OF ls_time,start TYPE timestampl,now TYPE timestampl,elapsed TYPE tzntstmpl, " 目前已運行時間limit TYPE tzntstmpl VALUE 3, " 最大等待時間END OF ls_time.GET TIME STAMP FIELD ls_time-start.WHILE ls_time-elapsed < ls_time-limit.SELECT SINGLE * INTO @DATA(LS_XXX) FROM XXXX WHERE ...IF LS_XXX IS NOT INITIAL.EXIT.ENDIF.GET TIME STAMP FIELD ls_time-now.ls_time-elapsed = cl_abap_tstmp=>subtract(tstmp1 = ls_time-nowtstmp2 = ls_time-start).ENDWHILE. " elapsed time
?4:使用模式為 U 或 V 的 ENQUEUE_XXXX 功能模塊
當您使用適當的功能模塊并使用模式 U、V(或 W)時,它將檢查鎖是否沖突。此處的 SAP 幫助示例:使用鎖定模式 U、V 和 W - SAP 鎖定概念 - SAP 庫中對此進行了詳細說明。這里沒有提到的是?_WAIT?參數。將此參數設置為 (abap_true 或 'X') 將使函數調用等待預定時間以釋放鎖。美妙之處在于,這不僅適用于您設置鎖定的標準模式,而且還適用于碰撞檢查。
CALL FUNCTION 'ENQUEUE_EVVBAKE'EXPORTINGmode_vbak = 'V' " Lock mode for table VBAKvbeln = l_sales_order " 02th enqueue argument_wait = abap_trueEXCEPTIONSforeign_lock = 1system_failure = 2others = 3.
這種方法的好處是無需手動實現等待邏輯。
5:增強
如果以上方式都不能滿足需求,則可以考慮將BAPI復制出來,找到其中控制異步的邏輯,通過增強來添加同步提交控制參數,使得BAPI以同步方式提交,一個案例如下:SAP CO11N BAPI_PRODORDCONF_CREATE_TT連續報工異步更新導致COGI解決方案-CSDN博客https://blog.csdn.net/DeveloperMrMeng/article/details/139811212?spm=1001.2014.3001.5501SAP 報工BAPI中的 UPDATA TASK 和 BACKGROUND TASK_abap in backround task 和in update task的區別-CSDN博客
https://blog.csdn.net/DeveloperMrMeng/article/details/140174352?spm=1001.2014.3001.5501
參考鏈接:
Updates in the SAP System (BC-CST-UP) | SAP Help Portalhttps://help.sap.com/docs/SAP_NETWEAVER_701/6d9bbcd26c4b101488b4a6a282b09136/5f6f8337dd34ca76e10000009b38f8cf.html?locale=en-US&q=V2%20Update%28Asynchronous%20Update%29
以上,如有不對,歡迎指正。