6.5数据一致性
6.5.1 SAP LUW与DB LUW
1.LUW概念:在SAP系统中,两个数据一致状态中的时间间隔为LUW(Logical Unit of Work),每一个LUW都需要以一个提交(COMMIT)或者返回(ROLLBACK)作为结束标志.如果以提交操作结束则进行所有更新操作,而返回操作则取消所有数据库表的更改.
2.数据库LUW:这是底层数据库自身提供的保持数据一致性的机制,与SAP系统无关,对于ABAP程序来说,主要的问题在于如何确定数据库的LUW的触发时机,一个工作过程总是在下述情况下结束一个数据库LUW并隐式地进行数据库提交:
l 当一个对话步骤(Dialog step)结束,即显示一个新屏幕给用户时.
l 在另一个工作过程继续程序的执行,这一般出现在RFC(远程功能模块)的调用或返回过程中.
相应地,下列情况将使数据库隐式地进行返回操作:
l 当前ABAP程序出现运行错误.
l 一个ABAP程序因类型A或X的消息而导致中止.
3.SAP LUW:一个SAP LUW可以包含多个对话步骤,即多个数据库LUW,但一个OPEN SQL语句不能被分隔为几个对话步骤,即通过SAP LUW可以将多个数据库LUW进行捆绑,并保存整体初始状态,不进行真正的数据库修改,当SAP LUW中的最后一个数据库LUW结束时,再进行整体修改,或者整体取消操作.
SAP LUW提供两种具体数据库LUW捆绑机制:
l 在定义FUNCTION时将其定义为Update module,同时在调用时用如下方式:CALL FUNCTION ...IN UPDATE TASK.则该模块不是马上被执行,而是被放置于应用服务器中的一个特殊的更新工作过程(Update work process)中,因此可以将多个分布在不同对话过程中的类似模块捆扎在一起,当SAP LUW结束时,确保所有模块被同时成功执行或整体放弃,因此可通过该方式封装分布在不同对话过程中的所有数据库更新操作.一个SAP LUW显式提交方式:COMMIT WORT [AND WAIT].该语句结束SAP LUW并触发更新工作过程,该过程在同一个数据库LUW中进行更新操作,因而数据库LUW此时可以替代SAP开始进行一致性控制.这些进行更新工作的FUNCTION可以被设为同步(加AND WAIT)或异步模式.即是否要等到更新任务完成后才继续执行后续语句.
l PERFORM ... ONCOMMIT [LEVEL n].效果与上面相同,此方法更高效,但此时子程序不能传递参数. LEVEL表示优先级,n取整数.n越小越先执行.
l ROLLBACK WORK.控制SAP LUW整体返回,在实现SAP LUW更新功能的FUNCTION或子程序内部不能使用此语句及COMMIT语句.
TABLES SPFLI.
DATA FLAG.
SPFLI-CARRID = 'LH'.SPFLI-CONNID = '1245'.
SPFLI-CITYFROM = ............
INSERT SPFLI.
IF SY-SUBRC <> 0.
FLAG = 'X'.
ENDIF.
SPFLI-CARRID = 'AA'.SPFLI-CONNID = '4574'.
SPFLI-CITYFROM = ............
INSERT SPFLI.
IF SY-SUBRC <> 0.
FLAG = 'X'.
ENDIF.
................
IF FLAG = 'X'.
ROLLBACK WORK.
ELSE.
COMMIT WORK.
ENDIF.
6.5.2 SAP数据锁定
用SE11创建一个锁定对象(lock object).激活它时会自动同时生成两个FUNCTION:ENQUEUE_<LOCK OBJECT>及DEQUEUE_<LOCK OBJECT>,调用这两个功能模块时可以分别锁定或解除锁定对象.被锁定的对象只有在解除锁定之后才可以被其它应用读取或写入.锁定模式:
l 共享锁定(shared):该模式允许多个用户访问指定表行,但只能读访问.任何时候都不允许写访问。
l 排他锁定(exclusive,not cumulative):该模式允许单个用户对指定表行进行读和写访问。其它用户不能访问该行。
l 扩展排他锁定(exclusive,cumulative): 该模式避免具有读写访问权限的单个用户获得对相同表行集的进一步锁定。当使用递归例程更新时,该模式很有用。
激活锁定对象导致系统生成用于锁定和解锁对象的特殊功能模块。这些功能模块称为:
调用 ENQUEUE/DEQUEUE功能模块
ENQUEUE_<lock-object-name>'用于锁定对象DEQUEUE_<lock-object-name>'用于解锁对象
运行时,在试图读或写之前可以锁定该数据库对象。要锁定对象,请在第一屏幕的PAI事件中调用功能模块ENQUEUE_<lock-object-name>。要解锁此对象,请调用DEQUEUE_<lock-object-name>。
ENQUEUE/DEQUEUE参数
ENQUEUE/DEQUEUE功能模块有下列参数集:
?arg和x_arg(ENQUEUE和DEQUEUE)
这两个EXPORTING参数,存在于锁定参数的每个字段arg中。将arg设置为所需的关键字字段值。如果该字段不需要特殊值,则忽略arg参数,或者将其设置为字段的初始值。如果要将字段的初始值作为实际选择值,请将x_arg设置为‘X’。
?_SCOPE(ENQUEUE)
如果事务不调用更新任务功能,则只在对话任务中更新。应该使用相应的DEQUEUE功能直接释放锁定。
如果调用任意的V1更新任务功能,请设置参数_SCOPE以告知系统应该如何释放SAP锁定。可能的值为:
1该值用于创建更新任务中不需要的锁定。在整个对话任务处理中保持使用_SCOPE=1设置的锁定,但该锁定并不能用于任意的更新任务请求。要保证不将锁定保持超过必要的时间,在事务结束时应该直接释放它(通过相应的DEQUEUE功能)。
在ROLLBACKWORK时释放:系统不释放使用_SCOPE=1设置的锁定。在编制反转程序时,请使用DEQUEUE功能。
2该值用于创建下列锁定:
-在更新任务触发之前在对话任务中使用
-一旦已经触发了更新任务,则只在更新任务中使用。
这意味着在COMMITWORK已经触发更新任务之后,如果该任务继续运行,则锁定不再可用于对话任务事务。系统在V1更新任务处理结束之后(或者在下一ROLLBACKWORK)释放锁定。
如果不指定_SCOPE,该值就是缺省值。不需要将DEQUEUE用于使用_SCOPE值创建的锁定。但是,如果_SCOPE=2,并且不调用更新任务功能,则不触发更新任务而且系统不释放锁定。
在ROLLBACKWORK释放:如果在提交前发生反转,则系统释放使用_SCOPE=2设置的锁定。在提交之后,锁定保持到更新任务处理结束。
3使用该值创建以下锁定:
-在触发更新任务之前在对话任务中使用
-在触发更新任务之后,由对话任务和更新任务使用。
也就是说,对话任务程序继续使用该锁定,甚至该更新任务功能正在运行时也是如此。在这种情况下,锁定由对话事务和更新任务功能所“共有”。
在V1更新任务处理之后的某个时刻系统释放锁定。但是,应该直接释放锁定(通过相应的DEQUEUE函数)以确保尽可能早地释放。
在ROLLBACKWORK释放:一旦已经触发更新任务,则使用_SCOPE=3设置的锁定有两个独立的所有者。要删除锁定,必须在对话任务和更新任务两方同时删除此锁定。如果在提交前发生反转,则在更新任务方释放锁定,但是对话任务方仍然保留它。如果在提交后发生反转,则系统在双方都不释放该锁定。在这种情况下,必须使用DEQUEUE功能在对话方直接释放该锁定。更新任务方将自动释放锁定。
如果用户在事务完成前已经退出了该事务(例如通过“/n”)或者程序异常终止,则系统释放所有锁定。V2功能也不能继承对话任务所创建的锁定。
?_WAIT(只ENQUEUE)
此EXPORTING参数告知:如果即将锁定的对象已经由其它用户锁定,ENQUEUE是否应该等待。如果要等待则将_WAIT设置为'X'。在这种情况下,系统试图以指定时间长度的重复间隔锁定该对象。如果这些尝试失败,则ENQUEUE导致FOREIGN_LOCK例外。
如果程序不想等待,则将_WAIT设置为其它任何值。在这种情况下,ENQUEUE导致FOREIGN_LOCK例外,并且将系统字段SY-MSGV1设置为已经拥有该锁定的用户名。
ENQUEUE例外
在调用ENQUEUE功能模块之后,应该检查在程序中该对象是否已经锁定。在功能模块中定义了下列例外:
?FOREIGN_LOCK
其它用户已经锁定了对象。系统字段SY-MSGV1包含该用户名。
?SYSTEM_FAILURE
一般系统错误。