19. 數據共享與傳遞
19.1. 程序調用、會話、SAP/ABAP內存 關系
“被調用程序插入型”是指:主調用程序(calling program)並不結束,當遇到Link 語句時,會去執行被調用程序(called program),當被調用程序結束后,調用程序回到調用處繼續執行;
“調用程序中止型”是指:調用程序(calling program)當遇到Link 語句時會立即中止,然后去執行被調用程序(called program),即使被調用程序執行完畢后,也不會返回到主調程序的調用處繼續執行;
SUBMIT<program> AND RETURN:中斷(不終止)當前運行的程序,啟動新的被調用程序<program>,當<program>運行完后,控制權又返回到被中斷的調用程序,繼續執行
CALL TRANSACTION <TCode>:可以插入一個具有事務代碼的ABAP程序,中斷當前運行的程序,待被調程序執行完后,再繼續執行主調程序
SUBMIT <program>:結束當前運行的程序,啟動新的被調用程序<program>
LEAVE TO TRANSACTION <TCode>:結束當前運行的程序,並啟動由事務碼<TCode>指定的ABAP程序。在程序中使用該語句的效果等同於用戶直接在命令行輸入“/n<TCode>”並執行的效果。
使用LEAVE TO TRANSACTION <TCode>調用另一程序時,可以在主調程序中使用“SET PARAMETER ID”將被傳遞的數據存儲到SAP memory中,在被調用的Tcode中可以使用“GET PARAMETER ID”來獲取,另外,也可以為被調用Tcode屏幕參數的data element設置parameter ID,這樣會自動的獲取與存儲該屏幕參數(只設置Data Element中的Parameter ID是不起作用的,請看后面)。
只有LEAVE TO TRANSACTION <TCode> 不能使用ABAP MEMORY共享數據(其它調用方式均可以),而應該使用SAP Memory;注,SUBMIT <program>調用后雖然不會返回到主調程序,但也是可以通過ABAP memory來傳遞數據
異步的Link Program:當遇到這種Function時,將會重新打開一個external session(外部會話,窗口會話),它並行地、獨立於當前的external session.
一個External session(外部會話,一個窗口就是一個外部會話)對應着一個ABAP MEMORY內存,所以同一個Window中的所有Internal session(內部會話,一個程序的調用就是一個內部會話)共用着同一個ABAP MEMORY,同一user logon session(用戶終端會話,登錄就會產生)中不同的window共用一個SAP MEMORY內存:
同一窗口中的不同程序共享同一個ABAP memory,同一用戶的不同窗口之間共享同一個SAP memory
當系統用戶登錄后,就會產生一個與該用戶對應的“用戶終端會話”(User Terminal Session),用戶可以開辟很多外部會話(即窗口,最多可打開6個窗口),在每個窗口會話(外部會話)中又可以先后執行多個ABAP程序(調用一個程序就會產生一個內部會話)
每一個外部會話都有一個叫ABAP Memory的內存區域,在該會話內部可以通過“EXPORT TO MEMORY”和“IMPORT FROM MEMORY”在該會話中的多個運行程序之間(即多個內部會話之間)進行數據共享,並可使用“FREE MEMORY ID”語句將共享數據從ABAP Memory中清除
SAP Memory是所有的會話(指同一用戶登錄會話中)都可以訪問的內存區域,因此可以通過“SET PARAMETER”與“GET PARAMETER”把數據保存在SAP內存中進行數據共享
所以,在同一個external session的Link program我們使用ABAP Memory進行傳遞數據;而在不同的external session間的Link program我們使用SAP Memory進行數據傳遞。
19.2. ABAP Memory數據共享
19.2.1. EXPORT
EXPORT {p1 = dobj1 p2 = dobj2 ...} | {p1 FROM dobj1 p2 FROM dobj2 ...} | (ptab) TO
| { MEMORY ID id }
| { DATABASE dbtab(ar) [FROM wa] [CLIENT cl] ID id }
| { SHARED MEMORY dbtab(ar) [FROM wa] [CLIENT cl] ID id }
| { SHARED BUFFER dbtab(ar) [FROM wa] [CLIENT cl] ID id }
1. {p1 = dobj1 p2 = dobj2 ...}與 {p1 FROM dobj1 p2 FROM dobj2 ...}的意義一樣,只是寫法不一樣,dobj1、dobj2…變量將會以p1、p2…名稱存儲到內存或數據庫中。p1、p2…名稱隨便取,如果p1、p2…與將要存儲的變量名相同時,只需寫變量名即可,即等號與 FROM 后面可以省略。p1、p2…這些名稱必須與IMPORT語句中相一致,否則讀取不出
2. (ptab):為動態指定需要存儲的變量,ptab內表結構要求是這樣的:只需要兩列,列名任意,但類型需要是字符型;第一列存儲如上面的p1、p2…名稱,第二列為上面的dobj1、dobj2…變量,如果變量與名稱相同,則也可以像上面一樣,省略第二列的值。兩列的值都必需要大寫,實例如下:
TYPES:BEGIN OF tab_type,
para TYPE string,"列的名稱任意,類型為字符型
dobj TYPE string,
END OF tab_type.
DATA:text1 TYPE string VALUE `TXT1`,
text2 TYPE string VALUE `TXT2`,
line TYPE tab_type,
itab TYPE STANDARD TABLE OF tab_type.
line-para = 'P1'."值都需要大寫
line-dobj = 'TEXT1'."值都需要大寫
APPEND line TO itab.
line-para = 'P2'.
line-dobj = 'TEXT2'.
APPEND line TO itab.
EXPORT (itab) TO MEMORY ID 'TEXTS'.
IMPORT p1 = text2 p2 = text1 FROM MEMORY ID 'TEXTS'.
WRITE: / text1,text2."TXT2 TXT1
CLEAR: text1,text2.
IMPORT (itab) FROM MEMORY ID 'TEXTS'.
WRITE: / text1,text2."TXT1 TXT2
3. MEMORY ID:將變量存儲到ABAP MEMORY內存(同一用戶的同一窗口Session)
4. DATABASE:將變量存儲到數據庫中;dbtab為簇數據庫表的名稱(如系統提供的標准表INDX);ar的值為區域ID,它將數據庫表的行分成若干區域,它必須被直接指定,且值是兩位字符,被存儲到簇數據庫表中的RELID字段中;id 的值會存儲到簇數據表中的RELID字段的下一用戶自定義字段中:
TYPES:BEGIN OF tab_type,
col1 TYPE i,
col2 TYPE i,
END OF tab_type.
DATA:wa_indx TYPE demo_indx_table,
wa_itab TYPE tab_type,
itab TYPE STANDARD TABLE OF tab_type.
WHILE sy-index < 100.
wa_itab-col1 = sy-index.
wa_itab-col2 = sy-index ** 2.
APPEND wa_itab TO itab.
ENDWHILE.
wa_indx-timestamp = sy-datum && sy-uzeit.
wa_indx-userid = sy-uname.
EXPORT tab = itab TO DATABASE demo_indx_table(sq) FROM wa_indx ID 'TABLE'.
TABLES: indx.
DATA: BEGIN OF i_tab OCCURS 100,
col1 TYPE i,
col2 TYPE i,
END OF i_tab.
DO 3000 TIMES.
i_tab-col1 = sy-index.
i_tab-col2 = sy-index ** 2.
APPEND i_tab.
ENDDO.
indx-aedat = sy-datum.
indx-usera = sy-uname.
indx-pgmid = sy-repid.
"省略了FROM選項,因為已經使用TABLES indx語句定義了名為indx的結構變量了
"Export時會自動將表工作區indx變量中的用戶字段存儲到簇數據庫表中
EXPORT i_tab TO DATABASE indx(HK) ID 'Key'.
WRITE: ' SRTF2',AT 20 'AEDAT',AT 35 'USERA',AT 50 'PGMID'.
ULINE.
"注:下面完全可以使用 IMPORT FROM DATABASE TO wa 語句來讀取用戶區字段
SELECT * FROM indx WHERE relid = 'HK'AND srtfd = 'Key'.
WRITE: / indx-srtf2 UNDER 'SRTF2',
indx-aedat UNDER 'AEDAT',
indx-usera UNDER 'USERA',
indx-pgmid UNDER 'PGMID'.
ENDSELECT.
SRTF2 AEDAT USERA PGMID
0 2011.10.12 ZHENGJUN YJZJ_TEST2
1 2011.10.12 ZHENGJUN YJZJ_TEST2
2 2011.10.12 ZHENGJUN YJZJ_TEST2
3 2011.10.12 ZHENGJUN YJZJ_TEST2
4 2011.10.12 ZHENGJUN YJZJ_TEST2
5. SHARED MEMORY/BUFFER :將數據存儲到SAP應用服務器上的內存中,可共同一服務上的所有程序訪問。兩種的作用是一樣的,最大不同是在數據達到最大內存限制時的處理方式不同:最大內存限制值分別是通過rsdb/esm/buffersize_kb (SHARED MEMORY)、rsdb/obj/buffersize (SHARED BUFFER)來設置的,當內存占用快滿時,SHARED MEMORY必須通過DELETE FROM SHARED MEMORY來手動清理,而SHARED BUFFER會自動刪除很少被使用到的數據(當然也可以通過DELETE FROM SHARED BUFFER手動及時的刪除不用的數據)
6. FROM wa:wa工作區類型可以參照簇數據庫dbtab類型,也可定義成只含有用戶數據字段的結構,它是用來設置簇數據庫表中SRTF2 與 CLUSTR兩個字段之間的用戶數據字段(參見簇數據表圖中的編號為5的用戶數據)的值,然后在Export時將相應的字段存儲到SRTF2字段與CLUSTR字段間的相應字段中去。如果使用“TABLES dbtab.”定義語句,可以省略“[FROM wa]”,也會默認將其存儲到數據庫表中,但如果沒有“TABLES dbtab.”這樣的定義語句,也沒有“[FROM wa]”選項時,將不會有數據存儲到簇數據庫表中的用戶字段中去
7. CLIENT cl:默認為當前客戶端,存儲到簇數據庫表中的MANDT字段中
19.2.2. IMPORT
IMPORT {p1 = dobj1 p2 = dobj2 ...} | {p1 TO dobj1 p2 TO dobj2 ...} | (ptab) FROM
| { MEMORY ID id }
| { DATABASE dbtab(ar) [TO wa] [CLIENT cl] ID id }
| { SHARED MEMORY dbtab(ar) [TO wa] [CLIENT cl] ID id }
| { SHARED BUFFER dbtab(ar) [TO wa] [CLIENT cl] ID id }
從簇數據表中讀取數據,各項參數與EXPORT是一樣的,請參考EXPORT各項解釋
TYPES:BEGIN OF tab,
col1 TYPE i,
col2 TYPE i,
END OF tab.
DATA:wa_indx TYPE demo_indx_table,
wa_itab TYPE tab,
itab TYPE STANDARD TABLE OF tab.
IMPORT tab = itab FROM DATABASE demo_indx_table(sq) TO wa_indx ID 'TABLE'.
WRITE: wa_indx-timestamp, wa_indx-userid.
ULINE.
LOOP AT itab INTO wa_itab.
WRITE: / wa_itab-col1, wa_itab-col2.
ENDLOOP.
TABLES indx.
DATA: BEGIN OF jtab OCCURS 100,
col1 TYPE i,
col2 TYPE i,
END OF jtab.
"注意:i_tab的名稱不能是其他的,必須與EXPORT語句中的分類存儲標簽名一樣。如果i_tab本身又是一個jtab類型的內表,則TO后面的jtab可以省略
IMPORT i_tab TO jtab FROM DATABASE indx(hk) ID 'Key'.
"注:在該程序中並沒有明顯的為indx工作區設置值,但由於使用了TABLES indx.語句定義了與indx簇數據庫表同名的結構變量,所以上面IMPORT會默認加上使用TO indx 選項
WRITE: / 'AEDAT:', indx-aedat,
/ 'USERA:', indx-usera,
/ 'PGMID:', indx-pgmid.
SKIP.
WRITE 'JTAB:'.
LOOP AT jtab FROM 1 TO 5.
WRITE: / jtab-col1, jtab-col2.
ENDLOOP.
AEDAT: 2011.10.12
USERA: ZHENGJUN
PGMID: YJZJ_TEST2
JTAB:
1 1
2 4
3 9
4 16
5 25
19.2.3. DELETE
DELETE FROM { {MEMORY ID id}
| {DATABASE dbtab(ar) [CLIENT cl] ID id}
| {SHARED MEMORY dbtab(ar) [CLIENT cl] ID id}
| {SHARED BUFFER dbtab(ar) [CLIENT cl] ID id} }.
用來清理EXPORT語句的存儲的數據。如果是針對MEMORY ID,則還可以使用 FREE MEMORY IDid與 DELETE FROM MEMORY ID id 作用一樣
DATA: id TYPE c LENGTH 4 VALUE 'TEXT',
text1 TYPE string VALUE 'Tina',
text2 TYPE string VALUE 'Mike'.
EXPORT p1 = text1 p2 = text2 TO SHARED BUFFER demo_indx_table(xy) ID id.
IMPORT p1 = text2 p2 = text1 FROM SHARED BUFFER demo_indx_table(xy) ID id.
DELETE FROM SHARED BUFFER demo_indx_table(xy) ID id.
"此語句會執行后,sy-subrc返回4
IMPORT p1 = text2 p2 = text1 FROM SHARED BUFFER demo_indx_table(xy) ID id.
19.3. SAP MEMORY數據共享
19.3.1. PARAMETERS/SELECT-OPTIONS選項MEMORY ID
Data Element中的Parameter ID的作用只是在屏幕設計時,起到一個輔助填充的作用,例如:當給某個屏幕字段命令時,如果這個字段的名稱為“表名(或結構)- 字段名” 形式時,回車時系統會提示:
當點擊Yes后,該字段的Parameter ID屬性會自動的設置為 MARA-MATNR字段所對應Data Element所設置的Parameter ID MAT,另外,From dict.也會自動被鈎上,但時,SET Parameter與GET Parameter 沒有自動鈎上,如果需要通過SAP Memory傳遞值,則還需要將這兩個手動鈎上(如上圖)
Data Element中的Parameter ID對選擇屏幕是沒有任何作用的,如下面的語句不能用來在SAP Memory中傳遞值:
PARAMETERS: m TYPE mara-matnr.
除非使用MEMORY ID 選項才起作用:
PARAMETERS: m TYPE mara-matnr MEMORY ID mat.
所以選擇屏幕中的參數選項 MEMORY ID的作用就等同於對話屏幕中的SET/GET Parameter,它們是作用是相同的,只不過一個用於選擇屏幕中,一個用於屏幕計中。
REPORT ztest_sap_memory_1.
*PARAMETERS: p_spa TYPE zdele_1 MEMORY ID zpara1.或者是下面這種寫法,根本不用參照zdele_1這個Data Element,因為Data Element中的Parameter ID對選擇屏幕參數沒有任何意義,所以只需要通過MEMORY ID選項動態的創建Parameter ID即可,不需要先選通過SE80或SM30來事先創建好
PARAMETERS: p_spa(10) MEMORY ID zpara1.
START-OF-SELECTION.
LEAVE TO TRANSACTION 'zsap_mem_2'.
zsap_mem_2事務碼對應的報表程序為:
DATA: mem(10).
GET PARAMETER ID 'ZPARA1' FIELD mem.
19.3.2. GET/SET PARAMETER ID
除了通過上面MEMORY ID 在同一用戶下不同窗口之間自動傳遞選擇屏幕參數外,也可以通過以下語句來手動傳遞屏幕參數以及非屏幕參數:
REPORT ztest_sap_memory_3.
PARAMETERS: p_spa TYPE zdele_1.
START-OF-SELECTION.
SET PARAMETER ID ’ZPARA1’ FIELD p_spa.
LEAVE TO TRANSACTION ’ztest_sap_memory_4’.
使用SE91為下面ztest_sap_memory_4程序創建了Tcode為:ztest_sap_memory_4
REPORT ztest_sap_memory_4.
PARAMETERS: p_spa TYPE zdele_1.
AT SELECTION-SCREEN OUTPUT."
GET PARAMETER ID ’ZPARA1’ FIELD p_spa.
GET/SET PARAMETER ID還可以與對話屏幕Parameter ID一起使用,如通過MM02輸入物料后,可以在程序中直接讀取:
DATA: material TYPE mara-matnr.
GET PARAMETER ID 'MAT' FIELD material.
WRITE:/ material.
19.4. DATABASE
SHARED BUFFER並不訪問(存儲)數據庫,而要存放在數據庫就應該用DATABASE
EXPORT DATABASE與普通數據庫操作的不同之處是,它適合大數據量的操作,系統自動將其拆分成多條記錄並存儲到數據庫中,比如圖片或文檔(甚至是程序中的某個內表,請參考后面的實例),而用IMPORT DATABASE的過程則相反,系統將把這些條相關記錄又自動組合起來成為一個整體。
如果要自定義INDX這樣的表,需要按以下表結構順序來定義:
該數據庫表結構要求:
①、可以有也可以無 MANDT字段
②、除開第一個字段MANDT(如果有的情況下),下一個字段必須是RELID,類型為CHAR 2,它是用來存儲area ID,系統會根據用戶在使用EXPORT語句保存數據時指定的area ID來填充它。
③、緊接下一個字段是一個任意長度(根據自己的需要定)的CHAR字段,名字也可以是隨便取的,該字段用為主鍵的一部分來使用,該字段的值也是在使用EXPORT語句保存數據時使用ID選項指定的值。
④、下一個字段的名字必須是SRTF2,類型為INT4,用來存儲數據行號(大數據對象——如圖片、文件、程序中的內表對象等,要分成多行來存儲)。由於某個數據可能很大,需要多行來存儲,理念是可能達到2**31行,該字段會自動的由系統填充。
⑤、在SRTF2字段的后面,你可以包括任意數量及類型的數據字段,這些字段是用來管理大對象的相應信息(如文件名、文件類型、創建者等),當你在保存數據時系統不會自動的填充這些字段,所以在保存這些字段時,需要通過一個結構傳遞需要存儲的值(即EXPORT語句中的From選項所帶的結構)。
⑥、倒數第二個字段的名必須為CLUSTR,類型為INT2,它存儲了最后一個字段CLUSTD所存儲數據的長度(字節數),在使用EXPORT語句保存數據時系統會自動填充
⑦、最后一個字段的名必須是CLUSTD,並且數據類型為LRAW,其長度表示能最大存儲多少個字節的內容,如果大數據對象很大(一行存儲不下時),會分成多行來存儲,行號就存儲在前面的SRTF2字段中。
19.4.1. 將文件存入表中
注意:上面這個表中的SRTFD實際上沒用上,因為Export時,ID選項的值實質上存儲到了它前面的ZZKEY中了,所以可以去掉這個字段(一般會留名為SRTFD字段而去掉ZZKEY字段)。
PARAMETERS: p_file TYPE string OBLIGATORY.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.
CALL FUNCTION 'WS_FILENAME_GET'
EXPORTING
def_filename = '*.*'
def_path = 'c:\'
mask = ',*'
mode = 'O'
title = 'File select'
IMPORTING
filename = p_file.
START-OF-SELECTION.
DATA: il_data LIKE solix OCCURS 0 WITH HEADER LINE,
l_len TYPE i.
**Upload file
REFRESH: il_data.
CLEAR l_len.
CALL FUNCTION 'GUI_UPLOAD'
EXPORTING
filename = p_file
filetype = 'BIN'
IMPORTING
filelength = l_len
TABLES
data_tab = il_data."ABAP沒有二進制類型,X類型代替
EXPORT il_data TO DATABASE indx(YY) ID 'ZZZ' .
上面是直接將讀取到的文件的二進制數據內表存儲到簇數據庫表中,我也也可通過SCMS_BINARY_TO_XSTRING函數將讀取的二進制數據內表拼接成只有一行的二進制串,然后再存儲這個被轉換后的二進制串也可:
PARAMETERS: p_file TYPE string OBLIGATORY,
p_id LIKE ybc_file-zzkey OBLIGATORY,
p_ftype LIKE ybc_file-mimetype OBLIGATORY,
p_fname LIKE ybc_file-filename OBLIGATORY.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.
CALL FUNCTION 'WS_FILENAME_GET'
EXPORTING
def_filename = '*.*'
def_path = 'c:\'
mask = ',*'
mode = 'O'
title = 'File select'
IMPORTING
filename = p_file.
START-OF-SELECTION.
DATA: il_data LIKE solix OCCURS 0 WITH HEADER LINE,
l_len TYPE i.
**Upload file
REFRESH: il_data.
CLEAR l_len.
CALL FUNCTION 'GUI_UPLOAD'
EXPORTING
filename = p_file
filetype = 'BIN'
IMPORTING
filelength = l_len
TABLES
data_tab = il_data."X類型內表
CHECK il_data[] IS NOT INITIAL.
**Convert data
DATA: l_xstr TYPE xstring.
CLEAR l_xstr.
"將內表以X類型拼接成XString字符串
CALL FUNCTION 'SCMS_BINARY_TO_XSTRING'
EXPORTING
input_length = l_len
IMPORTING
buffer = l_xstr
TABLES
binary_tab = il_data.
**Save data
"wl_file用於填充ybc_file表中非規定字段
DATA: wl_file LIKE ybc_file.
wl_file-uname = sy-uname.
wl_file-aedtm = sy-datum.
wl_file-pgmid = sy-cprog.
wl_file-mimetype = p_ftype.
wl_file-filename = p_fname.
DATA: l_answer TYPE c.
EXPORT l_xstr = l_xstr TO DATABASE ybc_file(bc) FROM wl_file ID p_id .
19.4.2. 從表中讀取文件
DATA: il_data LIKE solix OCCURS 0.
IMPORT il_data FROM DATABASE indx(YY) ID 'ZZZ'.
CALL METHOD cl_gui_frontend_services=>gui_download
EXPORTING
" bin_filesize = l_bytes
filename = 'c:\1.jpg'
filetype = 'BIN'
CHANGING
data_tab = il_data.
與存儲文件一樣,如果存儲的是拼接好的二進制串,則要使用SCMS_XSTRING_TO_BINARY函數來還原后再下載:
PARAMETERS: p_key LIKE ybc_file-zzkey.
DATA: l_xstr TYPE xstring.
IMPORT l_xstr = l_xstr FROM DATABASE ybc_file(bc) ID p_key.
DATA: l_xstring TYPE xstring,
l_xcnt TYPE i,
l_bytes TYPE i.
TYPES: hex512(512) TYPE x.
DATA: tab_xstring TYPE TABLE OF hex512 WITH HEADER LINE.
"將Xstring以X類型視圖存儲到內表中
CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
EXPORTING buffer = l_xstr
TABLES binary_tab = tab_xstring.
DATA: l_ftype LIKE yhr_attach-mimetype,
l_fname LIKE yhr_attach-filename.
"二進內容需使用IMPORT語句中讀取,但其他字段除了可使用 IMPORT語句的TO選項來直接讀取外,還可以通過SQL直接查詢
SELECT SINGLE mimetype filename INTO (l_ftype,l_fname) FROM ybc_file
WHERE relid = 'BC' AND zzkey = p_key.
DATA: l_file_name TYPE string.
CONCATENATE 'C:\' l_fname '.' l_ftype INTO l_file_name.
CALL METHOD cl_gui_frontend_services=>gui_download
EXPORTING
bin_filesize = l_bytes
filename = l_file_name
filetype = 'BIN'
CHANGING
data_tab = tab_xstring[].
19.5. JOB間數據傳遞
有兩種方式:
l SHARED MEMORY/SHARED BUFFER
l 通過Cluster Databases