\--
**1**
**写在前面**
之前发表过《聊聊更新表时的隐式提交》一文,向大家介绍隐式提交,对于数据库操 作的作用
聊聊更新表时的隐式提交
斌将军,公众号:斌将军 [ 聊聊更新表时的隐式提交
](https://mp.weixin.qq.com/s?__biz=Mzg5OTg3ODg2MQ==&mid=2247485598&idx=1&sn=77ffb1a17f4d983ee3c12c7e924ae77d&chksm=c04dd23cf73a5b2aff9900d384a20811a571d77215ddba7408529af91ed1a1cf56055790217d&scene=21#wechat_redirect)
** 有粉丝看过后,提出了自己的疑问: **
首先解释一下,该粉丝大致的问题和代码含义为:
在创建销售订单增强中,当因为错误需要拦截单据创建时,需要用commit work记录日志数据到自建表。而由于使用了commit
work,导致更新自建表的同时,将生成单据的事务也提交,导致拦截失败,单据一同被创建出来。
最终采用了在增强中调用CALL...STARTING NEW TASK 方式,将更新自建表以及commit
work放在函数中,这样自建表更新成功,单据也没有受到CALL...STARTING NEW TASK 中commit work的影响,成功被拦截了。
所以对CALL...STARTING NEW TASK执行后,对主程序进行隐式提交有疑问,隐式提交就不会将单据创建出来吗?
正好借此机会,解释这位粉丝疑问的同时,向大家介绍DB LUW和SAP LUW。
**2**
**DB LUW**
**2.1**
**什么是DB LUW**
_ DB LUW(Database Logical Unit of
Work):又称数据库逻辑单元。为了保证一系列数据库操作,要么同时成功提交,要么同时失败回滚,就引入了DB LUW,DB LUW
是数据库管理系统(DBMS)层面上的一个概念。 _
**如下图:**
数据库从左侧开始(代表一个DB LUW开始),经过INSERT、UPDATE、DELETE多次操作,如果其中任何一项操作出现问题,则对DB
LUW开始以来的所有操作进行回滚,使数据库回滚到最左侧(最左侧,代表初始数据)。如果没有错误,执行到commit,则将这一个DB
LUW中的一系列操作更新到数据库(最右侧,代表最终数据),以此来保证数据库数据的一致性。
** 代码举例: **
DB
LUW,将多个数据库操作视为一组,即一个逻辑单元。如果代码中的1、2、3项操作全部成功,则COMMIT后表中有1条数据(1001);如果其中出现错误,发生回滚,则表中没有一条数据。
"--------------------@斌将军--------------------DATA:lt_dbluw TYPE TABLE OF ztluw01, ls_dbluw TYPE ztluw01.
CLEAR:ls_dbluw.ls_dbluw-werks = '1001'.ls_dbluw-werks = '1002'.APPEND ls_dbluw TO lt_dbluw."-----DB LUW 开始-----"1、插入INSERT ztluw01 FROM TABLE lt_dbluw.
"2、更新UPDATE ztluw01 SET werks = '1003' WHERE werks = '1002'.*DATA(lv_error) = 1 / 0."发生错误IF sy-subrc NE 0. ROLLBACK WORK.ENDIF."3、删除DELETE FROM ztluw01 WHERE werks = '1003'.IF sy-subrc NE 0. ROLLBACK WORK.ENDIF.
"全部提交COMMIT WORK."-----DB LUW 结束-----"--------------------@斌将军--------------------
**2.2**
**DB LUW的提交和回滚**
针对DB LUW的提交操作,SAP有显式和隐式两种提交方式:
** 显式提交: ** 通常为我们熟知的COMMIT WORK,以及通过函数DB_COMMIT等实现的提交操作
** 隐式提交: ** 即文章《聊聊更新表时的隐式提交》一文中向大家介绍的提交方式。 ** 所以, 隐式提交是针对DB LUW的提交方式。 **
相对应也有显式回滚和隐式回滚,道理一样,不再赘述。
**2.3**
**DB LUW的生命周期**
一个DB LUW伴随上一次提交或者回滚之后自动产生,当再次遇到提交或回滚时结束,完成一个DB
LUW的活动历程。其中的提交和回滚包含显式和隐式,此概念对于理解下文至关重要。
**3**
**SAP LUW**
**3.1**
**什么是SAP LUW**
_ SAP LUW(SAP Logical Unit of
Work):又称SAP逻辑单元。指的是,在SAP系统中执行的一系列业务逻辑操作,这些操作可能涉及到多个DB LUW操作,即一个SAP LUW
可能会包含多个DB LUW。 _ __
_ 为了能保证这一系列业务操作中的所有DB LUW全部成功或者全部失败,就引入了SAP LUW,SAP LUW 是SAP应用程序层面上的一个概念。 _
_ 在SAP中,事务代码处理往往会涉及到多个业务逻辑操作,每个操作可能包含一个或多个数据库操作。 _ __
** 如图举例说明: **
例如:当A进银行给B转账时,系统需要①查询A账户余额,②A账户扣款,③B账户打款,④保存结束。
如上文所说,当每一次屏幕调用,会触发隐式提交,则该DB
LUW就执行完毕。如果③过程给B打款中出现失败,则只能从B2回滚到B1结束,而不能回滚到①过程,那么②过程中A扣的钱就不翼而飞了。
为了防止以上情况出现,通过SAP LUW概念,将①②③④个DB LUW捆绑成一个SAP LUW,在最后一步中提交,保证4个DB
LUW要么同时成功,要么同时失败,维护业务数据的一致性。
那如何绑定呢?
**3.2**
**实现SAP LUW**
根据SAP官方解释,通常有两种办法实现,
**3.2.1**
**使用更新功能函数进行捆绑**
使用函数的更新模式,即CALL...IN UPDATE TASK,将主程序的数据库语句放入更新函数中。使用 IN UPDATE TASK
调用函数模块时,该模块及其函数参数将作为日志条目存储在名为 VBLOG 的特殊数据库表中。
当程序遇到 COMMIT WORK 语句时,执行函数模块。如果发生逻辑错误,程序可以使用 ROLLBACK WORK
语句终止更新,则函数模块不执行,并从表VBLOG中删除日志条目。
另外也可以通过SET UPDATE TASK LOCAL设置为本地更新提交。这种方式不会将更新记录写入数据库,而是放在内存中,提交和回滚触发的方式同理。
**3.2.2**
**使用子例程捆绑**
使用PERFORM subr ON { {COMMIT [LEVEL idx]} | ROLLBACK }调用子例程。同理,在系统到达下一个 COMMIT WORK 语句时执行。其中LEVEL可设置优先级,数值越小,优先级越高
**3.2.3**
**两者的区别**
1、PERFORM...ON COMMIT 相对于CALL FUNCTION...IN UPDATE
TASK具有更好的性能,因为更新数据不必写入额外的表,从而减少了数据库访问。
2、 缺点是不能在PERFORM…ON COMMIT中传递参数,要使用全局变量和ABAP内存传递,使用此方法传递数据时,存在相当大的数据不一致的危险。
**3.3**
**代码验证DB 和 SAP LUW区别**
**3.3.1**
**单纯DB LUW实现**
执行隐式提交时,第一条数据已经插入成功。由于中间隐式提交,所以最终即使回滚,第一次插入的数据仍然存在。
"--------------------@斌将军--------------------CLEAR:ls_dbluw.ls_dbluw-werks = '1001'."-----DB LUW 开始-----"1、插入INSERT ztluw01 FROM ls_dbluw."模拟业务操作过程中的隐式提交CALL FUNCTION 'ZLUW_01' STARTING NEW TASK 'TASK'."空逻辑函数"-----DB LUW 结束-----
CLEAR:ls_dbluw.ls_dbluw-werks = '1002'."-----DB LUW 开始-----"2、插入INSERT ztluw01 FROM ls_dbluw."模拟失败,导致回滚ROLLBACK WORK."-----DB LUW 结束-----"--------------------@斌将军--------------------**3.3.2**
**SAP LUW实现**
创建更新函数
** 更新模式: **
• 立即开始:代表V1方式,设置函数为高优先级V1并运行在同一SAP LUW中。更新出错后,可以在SM13里重新执行
• 立即启动(不可更新):代表V1方式,设置函数为高优先级V1并运行在同一SAP LUW中。出错后不可以在SM13里重新执行
• 启动已延迟:代表V2方式,设置函数为低优先级V2并运行在自己的更新事务中。延迟的更新主要用于不紧急的数据库更改(例如统计更新)。V1方式更新完成后触发。出错后更新函数可以重启
• 集中运行:代表V2方式,将此更新函数设置为低优先级V2并运行在自己的更新事务中。需使用Collective(RSM13005)程序手动或JOB方式执行
** V1与V2区别: **
• V1优先级高于V2,V2依赖于V1,适合执行需要在V1完成后进行的操作
• V1更新使用V1进程处理,V1进程名字一般为UPD,V1进程绑定独立的数据库进程。在V1进程中调度的更新函数如果更新失败,回滚,不再进行V2操作。成功则提交更改到数据库,同时删除所有的SAP锁
• V2更新使用V2进程处理,如果没有配置V2进程则共用V1进程,V2进程名字为UP2,V2更新在独立DB LUW中,V2更新回滚后不会影响到V1更新提交的数据,由于V1更新结束后会删除SAP的锁,所以V2更新是在没有逻辑锁的情况下进行的,V2更新出错后可以在SM13中重新执行
• V1 的执行模式可以为异步、同步或本地;V2只能为异步执行
** 如下代码: **
由于使用了更新函数,即使遇到隐式提交,也不更新。
最终如果成功COMMIT,则表中有两条数据;如果失败ROLLBACK,则表中没有一条数据。
"--------------------@斌将军--------------------"1、插入*INSERT ztluw01 FROM ls_dbluw."将更新操作放在update函数中执行CALL FUNCTION 'ZLUW_02' IN UPDATE TASK.
"模拟业务操作过程中的隐式提交CALL FUNCTION 'ZLUW_01' STARTING NEW TASK 'TASK'.
CLEAR:ls_dbluw.ls_dbluw-werks = '1002'."-----DB LUW 开始-----"2、插入INSERT ztluw01 FROM ls_dbluw."模拟失败,导致回滚"COMMIT WORK.ROLLBACK WORK."-----DB LUW 结束-----"--------------------@斌将军--------------------更新函数代码
"--------------------@斌将军--------------------FUNCTION ZLUW_02.*"-----------------------------------------------------*"*"更新函数模块:*"*"*"本地接口:*"-----------------------------------------------------
DATA:lt_dbluw TYPE TABLE OF ztluw01, ls_dbluw TYPE ztluw01.
CLEAR:ls_dbluw.ls_dbluw-werks = '1001'."1、插入INSERT ztluw01 FROM ls_dbluw.
ENDFUNCTION."--------------------@斌将军--------------------因此可以证实,更新函数,遇到隐式提交不会运行,遇到显式提交才会。以此来保证一系列数据库操作的同时成功或失败,而无惧切换屏幕等方式引起的隐式提交。
当更新失败,会在SM13中记录
**4**
**结语**
以上就是关于DB LUW和SAP LUW的介绍。回到开头,在系统创建销售订单时,将其一系列操作封装为SAP LUW,因此在增强中写commit
work将会更新之前的一系列数据库操作,订单创建成功。而使用隐式提交,对SAP LUW不起作用,故订单没有创建成功。
本篇文章,参考以下文档,让我获益良多,非常感谢。
https://help.sap.com/docs/SAP_NETWEAVER_701/6da3d9466c4b1014a5a2e370bd8c5dc8/417af4bfa79e11d1950f0000e82de14a.html?locale=en-
US
https://www.cnblogs.com/ricoo/p/15481087.html
** —— 希望本篇文章对您有所帮助 **——** **