Tag Archives: APBP

[repost ]关于SAP Lock

original:http://scnblogs.techweb.com.cn/tcsapbw/archives/995.html

1. DB Lock

当ABAP遇到DB更新statement(Insert, update, modify, delete)时,DB lock会自动为DB设上,这是真正物理上的lock.它的实质是,在DB上设置一个flag,所以只能设置一个DB lock for one table at the given time.但是这个DB Lock会自动被删除,当完成DB commit时。所以,DB Lock的lifeTime最长只能存于一个DB LUW。

同DB LUW一样,我们知道,在dialog program时,会有相当多的SAP LUW.而此时DB Lock就不再适用了。

(关于LUW,在笔记中有专门记载:【ABAP文档】SAP ABAP系统开发(中文)读后笔记).

所以,需要用到SAP Lock。

2. SAP Lock

SAP Lock不同于DB Lock,它不是物理上的Lock。它是独立于DB Lock的。另外它有一个很重要的特性就是,它会在Transaction ends或者db commit时自动release(如关闭了session等)。

当创建Lock object(SE11)并active时,会有相应的两个FM(加锁: ENQUEUE_*;解锁: DEQUEUE_*)会被创建。

锁对象可以通过SM12进行管理。

关于更多:

help.sap.com/saphelp_nw2004s/helpdata/en/c2/2d7037ecc92a7ee10000009b38f8cf/frameset.htm

(1)加锁: ENQUEUE_<Lock object>

调用该FM会实现Lock.

这里需要记录几个Parameter。

_MOD

Mode是最重要的一个参数。SAP提供以下三种类型的锁:

描述
S (Shared) Shared lock.

Several users (transactions) can access locked data at the same time in display mode. A request for another shared lock is accepted, even if it comes from another user. An exclusive lock set on an object that already has a shared lock will be rejected.

E (Exclusive) Exclusive lock.

An exclusive lock protects the locked object against all types of locks from other transactions. Only the same lock owner can reset the lock (accumulate).

X (eXclusive non-cumulative) Exclusive but not cumulative lock.

Exclusive locks can be requested several times from the same transaction and are processed successively. In contrast, exclusive but not cumulative locks can be called only once from the same transaction. Each further lock request will be rejected.

其中S型为称为read access lock;而E与X被称为write access lock;

关于S、E、X锁对象存在后,再加其他锁,是否会有排斥或者是否会允许加其他锁,在后面的第三部分<SAP lock应用实例>有单独的测试。

_SCOPE

首先在说scope前,需要指明有两个owner:一个是Dialog owner(owner_1)一个是update owner(owner_2).

参数 描述
_SCOPE = 1 锁仅属于owner_1;因此锁仅存于dialog transaction中。调用DEQUEUE_或者在transaction结束,而不是commit work或者rollback work时,来解锁
_SCOPE = 2 锁属于owner_2;当在程序使用call FM .. IN UPDATE TASK或者commit work时,owner_2就得到了该锁。锁会在update transaction完成后解掉。同时也可以使用rollback work来解掉。注意,commit work不会起作用。
_SCOPE = 3 锁属于owner_1与owner_2。也就是说其集合了上面两种特性。

从上面可以看出,如果第一个锁使用scope 1,第二个锁使用scope 2,那么其相当于一次使用scope 3.

_COLLECT

Collect是指锁对象应该”置于”哪里。

描述
space 不使用local Lock container。
X 使用local lock container。

在程序中发出一个lock request就会与lock administration交互一次,如果向多个object发出lock request就会与lock administration交互多次。可以通过lock container来减少与lock administration交互的次数,通过parameter _collect = ‘X’,lock request就会存储在local container中,直到调用FLUSH_ENQUEUE。所有的lock request发送出去后就会清空整个local container。如果local container中有一个lock不能被set,就会触发exception foreign lock,那么一个lock都不会被设置并会重新试着发出请求。可以通过FM:RESET_ENQUEUE删除lock container中的内容。

/部分引自网络

3. SAP Lock的应用实例

(1)单独测试S锁:如已存在S锁是否会拒绝其他锁

这里,主要测试三种类型的锁。

S类型锁对象:

 

 

E类型锁对象:

 

 

X类型锁对象:

 

 

测试程序1: 加S锁:

*&———————————————————————*

*& Report ZTEST_LOCK_1 *

*& *

*&———————————————————————*

*& Test Lock *

*& *

*&———————————————————————*

 

REPORT ZTEST_LOCK_1 no standard page heading .

 

* lock

 

CALL FUNCTION ‘ENQUEUE_EZ_YMOIVE_OP’

EXPORTING

MODE_YMOIVE_OP = ‘S’

AAYEAR = ‘2008′

CATEGORY = ‘FEM’

* X_AAYEAR = ‘ ‘

* X_CATEGORY = ‘ ‘

_SCOPE = ‘2′

_WAIT = ‘ ‘

_COLLECT = ‘ ‘

EXCEPTIONS

FOREIGN_LOCK = 1

SYSTEM_FAILURE = 2

OTHERS = 3.

IF SY-SUBRC <> 0.

write:/ ‘Lock faild!’.

else.

write:/ ‘Lock successed!’.

ENDIF.

 

这里,使用edison_tc用户执行两次该程序;并使用edison_tc3这个用户执行该程序:

 

 

通过这里,我们可以发现:对于S型的锁是可以加多次的。这里如果退出SE38执行结果就会自动release一个锁。

 

测试程序2:加E锁:

*&———————————————————————*

*& Report ZTEST_LOCK_2 *

*& *

*&———————————————————————*

*& Add E lock *

*& *

*&———————————————————————*

 

REPORT ZTEST_LOCK_2 no standard page heading .

 

* add E lock

CALL FUNCTION ‘ENQUEUE_EZ_YMOIVE_OP_E’

EXPORTING

MODE_YMOIVE_OP = ‘E’

AAYEAR = ‘2008′

CATEGORY = ‘FEM’

* X_AAYEAR = ‘ ‘

* X_CATEGORY = ‘ ‘

_SCOPE = ‘2′

_WAIT = ‘ ‘

_COLLECT = ‘ ‘

EXCEPTIONS

FOREIGN_LOCK = 1

SYSTEM_FAILURE = 2

OTHERS = 3.

IF SY-SUBRC <> 0.

write:/ ‘Lock faild!’.

else.

write:/ ‘Lock successed!’.

ENDIF.

 

上面已经加了S锁,如果此时,再执行该程序:

 

 

此时执行失败,也就是说S锁后不能再加E锁。

 

测试程序3:添加X锁

*&———————————————————————*

*& Report ZTEST_LOCK_3 *

*& *

*&———————————————————————*

*& Add X lock *

*& *

*&———————————————————————*

 

REPORT ZTEST_LOCK_3 .

 

* add E lock

CALL FUNCTION ‘ENQUEUE_EZ_YMOIVE_OP_X’

EXPORTING

MODE_YMOIVE_OP = ‘E’

AAYEAR = ‘2008′

CATEGORY = ‘FEM’

* X_AAYEAR = ‘ ‘

* X_CATEGORY = ‘ ‘

_SCOPE = ‘2′

_WAIT = ‘ ‘

_COLLECT = ‘ ‘

EXCEPTIONS

FOREIGN_LOCK = 1

SYSTEM_FAILURE = 2

OTHERS = 3.

IF SY-SUBRC <> 0.

write:/ ‘Lock faild!’.

else.

write:/ ‘Lock successed!’.

ENDIF.

 

上面已经加了S锁,如果此时,再执行该程序:

 

 

此时执行失败,也就是说S锁后不能再加X锁。

综上,验证了:

S型锁后,可以再加read access lockS),但不接受write access lockE/X;


(2)单独测试E锁:如已存在E锁是否会拒绝其他锁

同时,如果第一次锁上了E锁,SM12:

 

那么无论是以Edison_tc以及edison_tc3再运行去加其他锁,都会失败:

执行加S锁:

 

执行加E锁:

 

执行加X锁:

 

综上,验证了:

如果对于某对象已存在了E锁,那么它会拒绝其他任意的锁;

 

(3)单独测试X锁:如已存在X锁是否会拒绝其他锁

同时,如果第一次锁上了X锁,SM12:

 

那么无论是以Edison_tc以及edison_tc3再运行去加其他锁,都会失败:

执行加S锁:

 

执行加E锁:

 

执行加X锁:

 

综上,验证了:

如果对于某对象已存在了X锁,那么它会拒绝其他任意的锁;

 

(4)累加测试1:在同一程序对同一对象先有S锁后,再E/X锁依次进行加锁

测试程序:

加锁顺序:SàEàX

*&———————————————————————*

*& Report ZTEST_LOCK_4 *

*& *

*&———————————————————————*

*& *

*& *

*&———————————————————————*

 

REPORT ZTEST_LOCK_4 No standard page heading .

 

*1st: add S lock

CALL FUNCTION ‘ENQUEUE_EZ_YMOIVE_OP’

EXPORTING

MODE_YMOIVE_OP = ‘S’

AAYEAR = ‘2008′

CATEGORY = ‘FEM’

* X_AAYEAR = ‘ ‘

* X_CATEGORY = ‘ ‘

_SCOPE = ‘2′

_WAIT = ‘ ‘

_COLLECT = ‘ ‘

EXCEPTIONS

FOREIGN_LOCK = 1

SYSTEM_FAILURE = 2

OTHERS = 3.

IF SY-SUBRC <> 0.

write:/ ‘1st: add S lock:Lock faild!’.

else.

write:/ ‘1st: add S lock:Lock successed!’.

ENDIF.

 

*2nd: add E lock

CALL FUNCTION ‘ENQUEUE_EZ_YMOIVE_OP_E’

EXPORTING

MODE_YMOIVE_OP = ‘E’

AAYEAR = ‘2008′

CATEGORY = ‘FEM’

* X_AAYEAR = ‘ ‘

* X_CATEGORY = ‘ ‘

_SCOPE = ‘2′

_WAIT = ‘ ‘

_COLLECT = ‘ ‘

EXCEPTIONS

FOREIGN_LOCK = 1

SYSTEM_FAILURE = 2

OTHERS = 3.

IF SY-SUBRC <> 0.

write:/ ‘2nd: add E lock:Lock faild!’.

else.

write:/ ‘2nd: add E lock:Lock successed!’.

ENDIF.

 

*3rd: add X lock

CALL FUNCTION ‘ENQUEUE_EZ_YMOIVE_OP_X’

EXPORTING

MODE_YMOIVE_OP = ‘X’

AAYEAR = ‘2008′

CATEGORY = ‘FEM’

* X_AAYEAR = ‘ ‘

* X_CATEGORY = ‘ ‘

_SCOPE = ‘2′

_WAIT = ‘ ‘

_COLLECT = ‘ ‘

EXCEPTIONS

FOREIGN_LOCK = 1

SYSTEM_FAILURE = 2

OTHERS = 3.

IF SY-SUBRC <> 0.

write:/ ‘3rd: add X lock:Lock faild!’.

else.

write:/ ‘3rd: add X lock:Lock successed!’.

ENDIF.

 

执行后:

 

同时,SM12查看锁对象:

 

如果我们调整一下执行顺序: SàXàE

 

综上,验证了:

在同一程序中对同一对象进行多次请求不同锁时:如果对象已存在了S锁,那么它可以接受ES锁,而拒绝X;(注:对于加了S锁后再加S锁,在上面不同的program下已验证,更别提在同一个program下,也可以测试验证)

 

(5)累加测试2:在同一程序对同一对象先有E锁后,再S/X锁依次进行加锁

测试程序:

加锁顺序:EàSàXàE(再加一把E锁)

*&———————————————————————*

*& Report ZTEST_LOCK_5 *

*& *

*&———————————————————————*

*& *

*& *

*&———————————————————————*

 

REPORT ZTEST_LOCK_5 No standard page heading .

 

*1st: add E lock

CALL FUNCTION ‘ENQUEUE_EZ_YMOIVE_OP_E’

EXPORTING

MODE_YMOIVE_OP = ‘E’

AAYEAR = ‘2008′

CATEGORY = ‘FEM’

* X_AAYEAR = ‘ ‘

* X_CATEGORY = ‘ ‘

_SCOPE = ‘2′

_WAIT = ‘ ‘

_COLLECT = ‘ ‘

EXCEPTIONS

FOREIGN_LOCK = 1

SYSTEM_FAILURE = 2

OTHERS = 3.

IF SY-SUBRC <> 0.

write:/ ‘1st: add E lock:Lock faild!’.

else.

write:/ ‘1st: add E lock:Lock successed!’.

ENDIF.

 

*2nd: add S lock

CALL FUNCTION ‘ENQUEUE_EZ_YMOIVE_OP’

EXPORTING

MODE_YMOIVE_OP = ‘S’

AAYEAR = ‘2008′

CATEGORY = ‘FEM’

* X_AAYEAR = ‘ ‘

* X_CATEGORY = ‘ ‘

_SCOPE = ‘2′

_WAIT = ‘ ‘

_COLLECT = ‘ ‘

EXCEPTIONS

FOREIGN_LOCK = 1

SYSTEM_FAILURE = 2

OTHERS = 3.

IF SY-SUBRC <> 0.

write:/ ‘2nd: add S lock:Lock faild!’.

else.

write:/ ‘2nd: add S lock:Lock successed!’.

ENDIF.

 

*3rd: add X lock

CALL FUNCTION ‘ENQUEUE_EZ_YMOIVE_OP_X’

EXPORTING

MODE_YMOIVE_OP = ‘X’

AAYEAR = ‘2008′

CATEGORY = ‘FEM’

* X_AAYEAR = ‘ ‘

* X_CATEGORY = ‘ ‘

_SCOPE = ‘2′

_WAIT = ‘ ‘

_COLLECT = ‘ ‘

EXCEPTIONS

FOREIGN_LOCK = 1

SYSTEM_FAILURE = 2

OTHERS = 3.

IF SY-SUBRC <> 0.

write:/ ‘3rd: add X lock:Lock faild!’.

else.

write:/ ‘3rd: add X lock:Lock successed!’.

ENDIF.

 

*4th: add E lock again

CALL FUNCTION ‘ENQUEUE_EZ_YMOIVE_OP_E’

EXPORTING

MODE_YMOIVE_OP = ‘E’

AAYEAR = ‘2008′

CATEGORY = ‘FEM’

* X_AAYEAR = ‘ ‘

* X_CATEGORY = ‘ ‘

_SCOPE = ‘2′

_WAIT = ‘ ‘

_COLLECT = ‘ ‘

EXCEPTIONS

FOREIGN_LOCK = 1

SYSTEM_FAILURE = 2

OTHERS = 3.

IF SY-SUBRC <> 0.

write:/ ‘4th: add E lock again:Lock faild!’.

else.

write:/ ‘4th: add E lock again:Lock successed!’.

ENDIF.

 

执行后:

 

同时SM12查看lock object:

 

综上,验证了:

在同一程序中对同一对象进行多次请求不同锁时:如果对象已存在了E锁,那么它可以接受ES锁,而拒绝X;

 

(6)累加测试3:在同一程序对同一对象先有X锁后,再S/E锁依次进行加锁

测试程序:

加锁顺序:XàSàEàX(再加一把X锁)

*&———————————————————————*

*& Report ZTEST_LOCK_4 *

*& *

*&———————————————————————*

*& *

*& *

*&———————————————————————*

 

REPORT ZTEST_LOCK_4 No standard page heading .

 

*1st: add X lock

CALL FUNCTION ‘ENQUEUE_EZ_YMOIVE_OP_X’

EXPORTING

MODE_YMOIVE_OP = ‘X’

AAYEAR = ‘2008′

CATEGORY = ‘FEM’

* X_AAYEAR = ‘ ‘

* X_CATEGORY = ‘ ‘

_SCOPE = ‘2′

_WAIT = ‘ ‘

_COLLECT = ‘ ‘

EXCEPTIONS

FOREIGN_LOCK = 1

SYSTEM_FAILURE = 2

OTHERS = 3.

IF SY-SUBRC <> 0.

write:/ ‘1st: add X lock:Lock faild!’.

else.

write:/ ‘1st: add X lock:Lock successed!’.

ENDIF.

 

*2nd: add S lock

CALL FUNCTION ‘ENQUEUE_EZ_YMOIVE_OP’

EXPORTING

MODE_YMOIVE_OP = ‘S’

AAYEAR = ‘2008′

CATEGORY = ‘FEM’

* X_AAYEAR = ‘ ‘

* X_CATEGORY = ‘ ‘

_SCOPE = ‘2′

_WAIT = ‘ ‘

_COLLECT = ‘ ‘

EXCEPTIONS

FOREIGN_LOCK = 1

SYSTEM_FAILURE = 2

OTHERS = 3.

IF SY-SUBRC <> 0.

write:/ ‘2nd: add S lock:Lock faild!’.

else.

write:/ ‘2nd: add S lock:Lock successed!’.

ENDIF.

 

 

*3rd: add E lock

CALL FUNCTION ‘ENQUEUE_EZ_YMOIVE_OP_E’

EXPORTING

MODE_YMOIVE_OP = ‘E’

AAYEAR = ‘2008′

CATEGORY = ‘FEM’

* X_AAYEAR = ‘ ‘

* X_CATEGORY = ‘ ‘

_SCOPE = ‘2′

_WAIT = ‘ ‘

_COLLECT = ‘ ‘

EXCEPTIONS

FOREIGN_LOCK = 1

SYSTEM_FAILURE = 2

OTHERS = 3.

IF SY-SUBRC <> 0.

write:/ ‘3rd: add E lock:Lock faild!’.

else.

write:/ ‘3rd: add E lock:Lock successed!’.

ENDIF.

 

*4th: add X lock again

CALL FUNCTION ‘ENQUEUE_EZ_YMOIVE_OP_X’

EXPORTING

MODE_YMOIVE_OP = ‘X’

AAYEAR = ‘2008′

CATEGORY = ‘FEM’

* X_AAYEAR = ‘ ‘

* X_CATEGORY = ‘ ‘

_SCOPE = ‘2′

_WAIT = ‘ ‘

_COLLECT = ‘ ‘

EXCEPTIONS

FOREIGN_LOCK = 1

SYSTEM_FAILURE = 2

OTHERS = 3.

IF SY-SUBRC <> 0.

write:/ ‘4th: add X lock again:Lock faild!’.

else.

write:/ ‘4th: add X lock again:Lock successed!’.

ENDIF.

 

执行后:

 

同时SM12查看lock object:

 

综上,验证了:

在同一程序中对同一对象进行多次请求不同锁时:如果对象已存在了X锁,同在不同的Program(Transaction)进行加锁一样,它会拒绝其他任何类型的锁。

 

4. SAP Lock的附加

(1)为什么需要使用S锁

从前面我们的应用实例中我们知道:对于在不同的Program或者transaction中对同一对象进行请求加S锁时,是完全可以接受的。同时,在同一程序对同一对象再进行S、E类型的加锁也是可以接受的。

其中,对于在同一程序同一对象加S锁后再加S和E可以接受,比较容易理解,毕竟是在同一个程序(也可以理解为同一user)。

但对于不同program/transaction可以都接受S锁,那疑问也许就出现了:既然S锁不排它(不同的transaction或program都可以加S)为什么还需要S锁呢?

首先,得有一个“常识”性概念:在我们对数据库进行操作时,对DB进行读取操作,需要加read access(S)锁;对DB进行写操作,需要加write access(E/X)锁;

其次:S锁的作用就是共享型、同时保证共享的DB数据不被修改(Write-access).

这样,就容易理解了:当多个program需要读数据时,使用S锁是接受的,所以多个program可以同时read相同的数据库;但限制写操作的执行。

因为我们平常在进行ABAP开发过程中,很少去遵循(读DB加read-access lock;修改DB加write-access lock),所以导致了不容易理解S锁的作用.

因为ABAP Developer是万能的,正如所想的那样,因为SAP Lock是独立于数据库的也就不是物理性的锁,所以,即使我们的DB上加了E甚至X锁后,我们仍然可以单独使用ABAP语句去read或者去write这个DB。

所以,为了更好地使用锁也为了更好地理解锁,还是遵循(读DB加read-access lock;修改DB加write-access lock)这么一个法则吧。

(2)E锁与X锁的区别

在ABAP中,我们经常遇到的问题就是:能说说E锁与X锁的区别吗?好像我要加锁时,加E或加X都能满足我把这个DB锁住了其他用户无法用,也就达到我们的需求了?

在前面第三部分,已经非常详尽地测试并说明了这二者的区别:

如果是不同的program/transaction分别加锁,那么E、X至少在表现上是没有区别的,都能满足我们的需求:一次加锁后,其他加锁不成功。

但是,如果是在相同的program中对相同的对象(DB)进行加锁,那么E与X就有区别了: E锁是可累加的,也就是说加了E锁后可以再接受E、S;而X锁是不可累加的,也就是加了X锁后,不接受任何其他的锁。

另外关于Lock的使用,请查阅:【Lock】关于Lock (二)