SAP是一个C/S结构,对数据库LUW在程序中会有一些隐式的DB Commit:
A、当系统输出一个屏幕的时候
B、当系统输出一个Message的时候,尤其是I类型的message( 会出现一个弹出框 )
C、当执行RFC的时候(普通的function不会,意味着可以通过一个commit跨function控制lLUW )
D、CALL Transaction或者sunmit <program name>,
但是在做dialog程序的时候又不得不需要程序做到只有一个luw,这样可以保持数据的一致性。
这时候对不复杂的程序我们可以在初期用内表传递数据,而不是直接update db,但是对于复杂的逻辑,之前已经有现成的函数或者BAPI,我们难以把原有函数copy出来最一些修改,这时候可以通过update function来把这些逻辑几种存放在一个SAP LUW。
SAP LUW:系统中一个DB LUW是不能够完全保证数据一致性的,但是SAP LUW可以跨screen,对多个DB LUW进行绑定,会在最后一个DB LUW提交,是的隐式的db commit不是阵阵的提交。
启用SAP LUW 的三种方法:
1)、update function 的更新方式分为同步、本地、异步;
2)、通过事务RFC(TRFC),CALL FUNCTION IN BACKGROUND TASK | UNIT,把RFC注册成并发的异步执行
3)、通过子程序PERFORM,(perform ....... on commit )
1)、update function 的更新方式分为同步、本地、异步;
1、同步RFC ,其执行基于同步通信模式,远程调用时,通信双方都可以使用,调用程序等待远程调用功能处理结束并返回结果。
2、异步RFC , 执行不依靠RFC服务器系统的可用性,被调用的远程功能启动,调用程序继续运行,两者相互分离,远程功能的结果可以稍后接受。日志:SM58
3、事务性RFC,属于异步通信模式,调用程序不接受调用结果而继续运行,但是不立即启动远程功能,。相关RFC可以捆绑只一个事务(即逻辑工作单元LUW),然后通过事务性处理,将LUW内部各个调用功能整体提交或者全部取消,且保证所有操作只执行一次,确保RFC功能的可靠和安全。
一个或者多个IN BACKGROUND TASK都通过一个COMMIT WORK控制;每个事务都有一个ID,不能指定EXPORTING参数,可以设定开始时间。
例如:IDOC的send的function,MASTER_IDOC_DISTRIBUTE
4、队列RFC ,QRFC是对TRFC的一个增强,控制传输数据的处理次序。
3、并行RFC , 实质为异步RFC,在功能上实现多个SAP系统或着同一SAP系统不同服务器,以及应用服务器内部各个工作过程的并行处理,
前3中是RFC的基本模式,队列RFC和并行RFC可以视为基本模式的扩展
同步:需等待返回结果,异步不需要,TRFC无法接受结果,同步异步RFC调用必须可用,TRFC则在调用的时候不必可用,异步只适用SAP内部之间,不能通过T类型的Partner连接至外部系统。
异步RFC和并发RFC的区别:
异步RFC:可以在RFC服务的时候调用,区别与同步执行,调用程序不需要等待结果,继续运行,远程调用功能与调用程序处理功能相互分离,功能返回结果可以了在后续过程被接受。
并发执行:异步调用时接受结果,异步执行可以在多个SAP ABAP系统上并行处理,同一内部系统使用异步调用,并将部分处理负载转移到其他服务器上,并发执行则是不指定运行的服务器,都是在当前应用服务器上处理。
Update function module的更新模式:
异步模式:dialog 程序和update function各自运行,dialog请求到log 透明表,用一个commit work结束,update function被commit 触发并开始运行这些请求,dialog程序继续运行,不会等待update 程序结束,update function在特殊的update work process中运行;
同步模式:用commit work and wait来触发一个同步更新,dialog程序会在update function执行结束再进行下一步处理,程序结束在进行下一步的处理,如果后续处理或者dialog程序的结束需要更新后的结果,要用同步模式,等待update 程序的过程中,dialog程序的dialog work process被释放,更新结束,会重新分配。
(注:commit work 即会进入异步模式,这时候先执行dialog程序,但是update function也会随后执行,此时dialog程序并不一定执行完毕。一般来说dialog响应时间较少,而update function会更长,所以异步更新更常见,也不排除特殊要求性;commit work and wait 要求执行完update function,才会执行dialog程序 )
本地模式:使用set update task local 来使用update module 在本地执行,用commit work 来关闭SAP LUW,更新汇总同一个dialog work process中进行,dialog等待更新完成(同步),local update 完成之后,会提交一个显示的DB COMMIT,DIALOG程序得以继续执行。LOCAL UPDATE更新请求不会写到VBLOG表中,而是在MAIN MEMORY,其速度笔同步和异步快一点,适合批量模式。且遇到COMMIT WORK 之后,本地执行不再有效。
*&---------------------------------------------------------------------*
*& Report ZTESTLIAN2
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
REPORT ztestlian_update_fm.
TABLES:spfli,sflight.
DATA: ok_code TYPE sy-ucomm,
save_ok TYPE sy-ucomm.
PARAMETERS:p_carrid TYPE spfli-carrid.
PARAMETERS:p_connid TYPE spfli-connid.
START-OF-SELECTION.
SELECT SINGLE * FROM spfli WHERE carrid = p_carrid AND connid = p_connid.
SELECT SINGLE * FROM sflight WHERE carrid = p_carrid AND connid = p_connid.
CALL SCREEN 0001.
*&---------------------------------------------------------------------*
*& Module EXIT INPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE exit INPUT.
save_ok = ok_code.
CLEAR:ok_code.
CASE save_ok.
WHEN 'BACK'.
LEAVE TO SCREEN 0.
WHEN 'EXIT'.
LEAVE TO SCREEN 0.
WHEN 'CANCEL'.
LEAVE PROGRAM.
ENDCASE.
ENDMODULE. " EXIT INPUT
*&---------------------------------------------------------------------*
*& Module STATUS_0001 OUTPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE status_0001 OUTPUT.
SET PF-STATUS 'STATUS_0001'.
* SET TITLEBAR 'xxx'.
SELECT SINGLE * FROM spfli WHERE carrid = spfli-carrid AND connid = spfli-connid.
SELECT SINGLE * FROM sflight WHERE carrid = p_carrid AND connid = p_connid.
ENDMODULE. " STATUS_0001 OUTPUT
*&---------------------------------------------------------------------*
*& Module USER_COMMAND_0001 INPUT
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
MODULE user_command_0001 INPUT.
save_ok = ok_code.
CLEAR:ok_code.
CASE save_ok.
WHEN 'SAVE1'.
PERFORM update_1.
WHEN 'SAVE2'.
PERFORM update_2.
ENDCASE.
ENDMODULE. " USER_COMMAND_0001 INPUT
*&---------------------------------------------------------------------*
*& Form UPDATE_1
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM update_1.
CALL FUNCTION 'Z_LIAN_UPDATE_FM1'
IN UPDATE TASK
EXPORTING
iv_connid = spfli-connid
iv_carrid = spfli-carrid
iv_planetype = sflight-planetype.
CALL SCREEN 0002.
ENDFORM. " UPDATE_1
*&---------------------------------------------------------------------*
*& Form UPDATE_2
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM update_2 .
CALL FUNCTION 'Z_LIAN_UPDATE_FM2'
IN UPDATE TASK
EXPORTING
iv_connid = spfli-connid
iv_carrid = spfli-carrid
iv_countryfr = spfli-countryfr
iv_cityfrom = spfli-cityfrom
iv_airpfrom = spfli-airpfrom
iv_countryto = spfli-countryto.
COMMIT WORK AND WAIT.
wait up to 5 seconds.
ENDFORM. " UPDATE_2
SE37中的update function还分4种模式,属于两种类型:V1和V2。
V1类型:1)、立即启动,如果发生错误可以用SM13手动重启更新,会清除有问题的应用程序错误;2)、立即启动(不可重启),发生错误是不可以重启;
V2类型:1)、延迟启动:V2类型出现错误,可以随时重新启动处理;2)、Collective run,V2更新的特殊模式,所有修改不直接更新,而是再V1更新之后,但只有在收集程序RSM13005被调用后
V1 和V2 对比:
1)、所有V1请求都在单独的DB LUW里,只有在V1执行后才会处理V2,V2也是在单独的LUW里执行。
2)、V2里处理的DB CHANGES一般都是紧接着V1的CHANGES( MAIN CHANGES )后执行
3)、V1可以分为可以重新启动和不可重新启动,V2发生的时候可以重新启动,再次处理。
4)、V2的collective run 是SAP 内部使用,相应的V2请求并不是在V1执行后直接执行,而且仅仅是在RSM130005被调用后才执行。
5)、V1请求,同步异步都会放在VBLOG这个table中,本地更新则是放在MAIN MEMORY,V2请求总是放在VBLOG中
6)、V1都会用UPD组颇为一个单独的DB LUW来处理,V1更新成功,系统会删除V1请求和所有V1更新任务上的锁,并设置DB COMMIT,然后触发V2,
下面再介绍以下update function怎么debug:
在debugging setting 中将Update debugging复选框,并点击保存,在函数中运行commit work 之后,会自动进入更新任务表SM13
Immediate start 表示v1方式更新,出错之后可以在SM13中重新执行;
Immediate start-no restart possible v1出错后不可以在SM13中再重新执行,有些更新脱离具体程序之后更新可能会带来数据不一致;
Start delayed 表示V2方式,在V1方式更新之后完成后触发,
Collective run表示 V2方式,需要用Collective( RSM13005 )程序手动或JOB执行
In update task 使用v1更新可以在commit work的时候执行所有的update function
分享一个实例:
需求在于为CJ20N和CN22修改预留单增加日志,但这都是集成模块,修改预留单数量在CN22中还会伴随网络,计划成本多部分的更新,在CJ20N在还会增加项目,WBS,SO等一系列内容的检查和更新,这一切的更新都是在多个PERFORM 或者FUNCTION中实现的,他们要想做到一致性必须要用到SAP LUW。
首先提交所用到的语法 commit work 和commit work and wait的区别就不再细说,我起初认为在提交的时候如果进入DEBUG模式,执行完更新SQL语句后在后面的update的函数在做SELECT的时候可以得到我更新后的值,所以我在commit work and wait 前面的一个增强点加上一个perform ... on commit,但实际上虽然dubug已经已经执行了这段代码,但是实际上并没有更新数据库,所以我还是在commit work and wait之后的增强点去写的这段逻辑,当然这多逻辑在前面没有执行提交语句的时候也是不会执行的,这是为了在后面的CJ20N里面保证数据依旧是一次提交的。
当然上面的那个问题可以通过 ABAP MEMORY来解决,但是可能需要在另一个做一下增强。
做好增强之后出现另一个问题,在项目和WBS提交的时候使用到的是 commit work 异步提交模式,此时我后面所写的增强逻辑在读数据库的时候,不能读到最新的状态,所以必须写上等待0.5秒。但是请注意:WAIT UP语句有提交数据库的作用,所以在增强里面是一般是禁止使用WAIT UP语句的,我这里是由于刚刚做完提交,所以没啥问题。但是如果必须在增强里面加上等待应使用如下函数:
CALL FUNCTION 'ENQUE_SLEEP'
EXPORTING
seconds = 1
EXCEPTIONS
OTHERS = 2.
注:两种语法都是Numeric类型,都应该是整数,上图中的0.5秒会被四舍五入变为1.