*---------------------------- 综述 SAP锁机制 ----------------------------
一、 SAP 为什么要设置锁:
1 ,保持数据的一致性
如果几个用户要访问同样的资源,需要找到一种同步访问的方法去保持数据的一致性。比如说,在航班预订系
统中,需要检查还有没有空座位,当检查的时候,你不想别人修改重要的数据(空座位的数量)。
2 ,仅仅用 Database 锁是不够的
数据库管理系统物理锁定了要修改的行记录,其他用户要等到数据库锁释放才能访问这个记录。
在 SAP 系统中,当一个新屏幕显示的时候会释放掉 Database 锁,因为屏幕的改变会触发一个隐式的 DB COMMIT
。如果数据是从好几个屏幕收集来的话,而且在这段时间内这些数据会分别被锁定,仅仅用 Database 锁就不够了。
SAP 系统在应用服务器层面有一个全局的 LOCK TABLE ,可以用来设置逻辑锁来锁定相关的表条目,并有
ENQUEUE 工作进程来管理这些锁。 SAP 锁是一种逻辑意义上的锁,有可能你锁定的表条目在 DATABASE 上根本就
不存在。
二、锁对象和其对应的 Function Module
在 SE11 里创建锁对象,自定义的锁对象都必须以 EZ 或者 EY 开头来命名。一个锁对象里只包含一个 PRIMARY
TABLE ,可以包含若干个 SECONDARY TABLE ,锁的模式有三种: E , S , X 。 LOCK PARAMETERS 里填写你要根
据哪些字段来锁定表条目。
模式 E :当更改数据的时候设置为此模式。
模式 S :本身不需要更改数据,但是希望显示的数据不被别人更改。
模式 X :和 E 类似,但是不允许累加,完全独占。
如果你在一个程序里成功对一个锁对象加锁之后,如果模式为 E ,其他用户不能再对这个锁对象加 E 、 X 、 S 模式
的任意一种锁;
如果你在一个程序里成功对一个锁对象加锁之后,如果模式为 X ,其他用户不能再对这个锁对象加 E 、 X 、 S 模式
的任意一种锁;
如果你在一个程序里成功对一个锁对象加锁之后,如果模式为 S ,其他用户不能再对这个锁对象加 E 、 X 模式的
锁,但是可以加 S 模式的锁;
如果你在一个程序里成功对一个锁对象加锁之后,如果模式为 E ,在这个程序,你还可以再对这个锁对象加 E 、 !!!
S 模式的锁, X 模式的不可以。
如果你在一个程序里成功对一个锁对象加锁之后,如果模式为 X ,在这个程序,你不可以再对这个锁对象加 E 、
X 、 S 模式的锁。
如果你在一个程序里成功对一个锁对象加锁之后,如果模式为 S ,在这个程序,你还可以再对这个锁对象加 S 模
式的锁,如果没有别的用户对其加 S 模式的锁,那么你还可以对其加 E 模式的锁。 X 模式的不可以。
当激活锁对象的时候,系统会自动创建两个 FM , ENQUEUE_< 锁对象名 > 和 DEQUEUE_< 锁对象名 > ,分别用来锁
定和解锁。
三、锁定和解锁
当用逻辑锁来锁定表条目的时候,系统会自动向 LOCK TABLE 中写入记录。
当调用设置锁的 FM 时, LOCK PARAMETERS 如果没有指明,系统会锁定整个表。当然, LOCK PARAMETER :
CLIENT 有点特殊,如果不指定,默认是 SY - MANDT ;如果指定相应的 CLIENT ,会锁定对应 CLIENT 上的相应的表
记录;如果设置为 SPACE ,则锁定涉及所有的 CLIENT 。
当逻辑锁设置失败后,一般会有两种例外。一个是 EXCEPTION : FOREIGN_LOCK ,意思是已经被锁定了;另一
个是 EXCEPTION : SYSTEM_FAILURE 。
有些情况下,程序中设置成功的逻辑锁会隐式的自己解锁。比如说程序结束发生的时候( MESSAGE TYPE 为 A
或者 X 的时候),使用语句 LEAVE PROGRAM , LEAVE TO TRANSACTION ,或者在命令行输入 /n 回车以后。
在程序的结束可以用 DEQUEUE FUNCTION MODULE 来解锁(当然如果你不写这个,程序结束的时候也会自动的
解锁),这个时候,系统会自动从 LOCK TABLE 把相应的记录删除。使用 DEQUEUE FUNCTION MODULE 来解锁的
时候,不会产生 EXCEPTION 。要解开你在程序中创建的所有的逻辑锁,可以用 FM : DEQUEUE_ALL .
四、上锁的一般步骤
先上锁,上锁成功之后,从数据库取数据,然后更改数据,接着更新到数据库,最后解锁。按照这个步骤,才
能保证更改完全运行在锁的保护机制下。
S : 共享锁 E : 写锁 X : 排他锁
*1. 使用TCODE: SE11,選擇最後一項[加鎖物件],輸入物件名稱(注意一定要以字母‘EZ’或 ‘EY’開頭,這是SAP內部規定的,如EZTESTING)
*2. 輸入名稱後,按新增,進入界面後輸入要加鎖的Table名,及加鎖類型(E:專用,累計;S:共享;X:專用,不累計)。保存後,系統會自動產生兩個函數: ENQUEUE_EZTESTING(加鎖)和 DEQUEUE_EZTESTING(解鎖)。
*3. 然後在更改記錄前調用加鎖函數對記錄進行鎖定,在修改完成或退出修改後一定要對記錄進行解鎖。
*4. 自定义加鎖及解鎖代碼(参照系统生成代码):(Table:ZTESTING,key: fieldKey)
*------------------------------------ 加鎖 -------------------------------
FORM lock_record USING p_key .
DATA : it_seqg3 TYPE seqg3 OCCURS 01 WITH HEADER LINE .
DATA : gname LIKE seqg3 - gname , garg LIKE seqg3 - garg .
DATA : BEGIN OF %ztesting ,
mandt TYPE ztesting - mandt ,
fieldkey TYPE ztesting - fieldkey ,
END OF %ztesting .
*---锁定函数初始化:
CALL 'C_ENQ_WILDCARD' ID 'HEX0' FIELD %ztesting .
*---对关键字的赋值
MOVE sy - mandt TO : %ztesting - mandt .
IF NOT p_key IS INITIAL .
MOVE p_key TO : %ztesting - fieldkey .
ENDIF .
gname = 'ZTESTING' .
garg = %ztesting .
*---读取是否已经被锁定
CALL FUNCTION 'ENQUEUE_READ'
EXPORTING
gclient = sy - mandt
gname = gname
garg = garg
TABLES
enq = it_seqg3 .
IF sy - subrc <> 0 .
MESSAGE ID sy - msgid TYPE sy - msgty NUMBER sy - msgno WITH sy - msgv1 sy - msgv2 sy - msgv3 sy - msgv4 .
ENDIF .
IF it_seqg3 IS NOT INITIAL .
DATA : cmessage ( 100 ) TYPE c .
CONCATENATE p_key ' 正由 ' it_seqg3 - guname ' 處理 !' INTO cmessage .
CONDENSE cmessage .
MESSAGE cmessage TYPE 'E' .
ELSE .
*---开始锁定记录
*加锁时,不管这个表中有没有这个条目,都会加锁成功(即sy-subrc = 0)。加锁后,再操作同一条目,会提示XXX正在处理!
CALL FUNCTION 'ENQUEUE_EZTESTING'
EXPORTING
mode_ztesting = 'E'
mandt = sy - mandt
zfieldkey = p_key
x_zfieldkey = ' '
_scope = '2'
_wait = ' '
_collect = ' '
EXCEPTIONS
foreign_lock = 1
system_failure = 2
OTHERS = 3 .
IF sy - subrc <> 0 .
MESSAGE ID sy - msgid TYPE sy - msgty NUMBER sy - msgno WITH sy - msgv1 sy - msgv2 sy - msgv3 sy - msgv4 .
ENDIF .
ENDIF .
ENDFORM . "lock_record
*------------------------------ 解鎖 -------------------------------------
FORM unlock_record USING p_key .
CALL FUNCTION 'DEQUEUE_EZTESTING'
EXPORTING
mode_ztesting = 'E'
mandt = sy - mandt
zfieldkey = p_key
x_zfieldkey = ' '
_scope = '3'
_synchron = ' '
_collect = ' ' .
一、 SAP 为什么要设置锁:
1 ,保持数据的一致性
如果几个用户要访问同样的资源,需要找到一种同步访问的方法去保持数据的一致性。比如说,在航班预订系
统中,需要检查还有没有空座位,当检查的时候,你不想别人修改重要的数据(空座位的数量)。
2 ,仅仅用 Database 锁是不够的
数据库管理系统物理锁定了要修改的行记录,其他用户要等到数据库锁释放才能访问这个记录。
在 SAP 系统中,当一个新屏幕显示的时候会释放掉 Database 锁,因为屏幕的改变会触发一个隐式的 DB COMMIT
。如果数据是从好几个屏幕收集来的话,而且在这段时间内这些数据会分别被锁定,仅仅用 Database 锁就不够了。
SAP 系统在应用服务器层面有一个全局的 LOCK TABLE ,可以用来设置逻辑锁来锁定相关的表条目,并有
ENQUEUE 工作进程来管理这些锁。 SAP 锁是一种逻辑意义上的锁,有可能你锁定的表条目在 DATABASE 上根本就
不存在。
二、锁对象和其对应的 Function Module
在 SE11 里创建锁对象,自定义的锁对象都必须以 EZ 或者 EY 开头来命名。一个锁对象里只包含一个 PRIMARY
TABLE ,可以包含若干个 SECONDARY TABLE ,锁的模式有三种: E , S , X 。 LOCK PARAMETERS 里填写你要根
据哪些字段来锁定表条目。
模式 E :当更改数据的时候设置为此模式。
模式 S :本身不需要更改数据,但是希望显示的数据不被别人更改。
模式 X :和 E 类似,但是不允许累加,完全独占。
如果你在一个程序里成功对一个锁对象加锁之后,如果模式为 E ,其他用户不能再对这个锁对象加 E 、 X 、 S 模式
的任意一种锁;
如果你在一个程序里成功对一个锁对象加锁之后,如果模式为 X ,其他用户不能再对这个锁对象加 E 、 X 、 S 模式
的任意一种锁;
如果你在一个程序里成功对一个锁对象加锁之后,如果模式为 S ,其他用户不能再对这个锁对象加 E 、 X 模式的
锁,但是可以加 S 模式的锁;
如果你在一个程序里成功对一个锁对象加锁之后,如果模式为 E ,在这个程序,你还可以再对这个锁对象加 E 、 !!!
S 模式的锁, X 模式的不可以。
如果你在一个程序里成功对一个锁对象加锁之后,如果模式为 X ,在这个程序,你不可以再对这个锁对象加 E 、
X 、 S 模式的锁。
如果你在一个程序里成功对一个锁对象加锁之后,如果模式为 S ,在这个程序,你还可以再对这个锁对象加 S 模
式的锁,如果没有别的用户对其加 S 模式的锁,那么你还可以对其加 E 模式的锁。 X 模式的不可以。
当激活锁对象的时候,系统会自动创建两个 FM , ENQUEUE_< 锁对象名 > 和 DEQUEUE_< 锁对象名 > ,分别用来锁
定和解锁。
三、锁定和解锁
当用逻辑锁来锁定表条目的时候,系统会自动向 LOCK TABLE 中写入记录。
当调用设置锁的 FM 时, LOCK PARAMETERS 如果没有指明,系统会锁定整个表。当然, LOCK PARAMETER :
CLIENT 有点特殊,如果不指定,默认是 SY - MANDT ;如果指定相应的 CLIENT ,会锁定对应 CLIENT 上的相应的表
记录;如果设置为 SPACE ,则锁定涉及所有的 CLIENT 。
当逻辑锁设置失败后,一般会有两种例外。一个是 EXCEPTION : FOREIGN_LOCK ,意思是已经被锁定了;另一
个是 EXCEPTION : SYSTEM_FAILURE 。
有些情况下,程序中设置成功的逻辑锁会隐式的自己解锁。比如说程序结束发生的时候( MESSAGE TYPE 为 A
或者 X 的时候),使用语句 LEAVE PROGRAM , LEAVE TO TRANSACTION ,或者在命令行输入 /n 回车以后。
在程序的结束可以用 DEQUEUE FUNCTION MODULE 来解锁(当然如果你不写这个,程序结束的时候也会自动的
解锁),这个时候,系统会自动从 LOCK TABLE 把相应的记录删除。使用 DEQUEUE FUNCTION MODULE 来解锁的
时候,不会产生 EXCEPTION 。要解开你在程序中创建的所有的逻辑锁,可以用 FM : DEQUEUE_ALL .
四、上锁的一般步骤
先上锁,上锁成功之后,从数据库取数据,然后更改数据,接着更新到数据库,最后解锁。按照这个步骤,才
能保证更改完全运行在锁的保护机制下。
S : 共享锁 E : 写锁 X : 排他锁
*1. 使用TCODE: SE11,選擇最後一項[加鎖物件],輸入物件名稱(注意一定要以字母‘EZ’或 ‘EY’開頭,這是SAP內部規定的,如EZTESTING)
*2. 輸入名稱後,按新增,進入界面後輸入要加鎖的Table名,及加鎖類型(E:專用,累計;S:共享;X:專用,不累計)。保存後,系統會自動產生兩個函數: ENQUEUE_EZTESTING(加鎖)和 DEQUEUE_EZTESTING(解鎖)。
*3. 然後在更改記錄前調用加鎖函數對記錄進行鎖定,在修改完成或退出修改後一定要對記錄進行解鎖。
*4. 自定义加鎖及解鎖代碼(参照系统生成代码):(Table:ZTESTING,key: fieldKey)
*------------------------------------ 加鎖 -------------------------------
FORM lock_record USING p_key .
DATA : it_seqg3 TYPE seqg3 OCCURS 01 WITH HEADER LINE .
DATA : gname LIKE seqg3 - gname , garg LIKE seqg3 - garg .
DATA : BEGIN OF %ztesting ,
mandt TYPE ztesting - mandt ,
fieldkey TYPE ztesting - fieldkey ,
END OF %ztesting .
*---锁定函数初始化:
CALL 'C_ENQ_WILDCARD' ID 'HEX0' FIELD %ztesting .
*---对关键字的赋值
MOVE sy - mandt TO : %ztesting - mandt .
IF NOT p_key IS INITIAL .
MOVE p_key TO : %ztesting - fieldkey .
ENDIF .
gname = 'ZTESTING' .
garg = %ztesting .
*---读取是否已经被锁定
CALL FUNCTION 'ENQUEUE_READ'
EXPORTING
gclient = sy - mandt
gname = gname
garg = garg
TABLES
enq = it_seqg3 .
IF sy - subrc <> 0 .
MESSAGE ID sy - msgid TYPE sy - msgty NUMBER sy - msgno WITH sy - msgv1 sy - msgv2 sy - msgv3 sy - msgv4 .
ENDIF .
IF it_seqg3 IS NOT INITIAL .
DATA : cmessage ( 100 ) TYPE c .
CONCATENATE p_key ' 正由 ' it_seqg3 - guname ' 處理 !' INTO cmessage .
CONDENSE cmessage .
MESSAGE cmessage TYPE 'E' .
ELSE .
*---开始锁定记录
*加锁时,不管这个表中有没有这个条目,都会加锁成功(即sy-subrc = 0)。加锁后,再操作同一条目,会提示XXX正在处理!
CALL FUNCTION 'ENQUEUE_EZTESTING'
EXPORTING
mode_ztesting = 'E'
mandt = sy - mandt
zfieldkey = p_key
x_zfieldkey = ' '
_scope = '2'
_wait = ' '
_collect = ' '
EXCEPTIONS
foreign_lock = 1
system_failure = 2
OTHERS = 3 .
IF sy - subrc <> 0 .
MESSAGE ID sy - msgid TYPE sy - msgty NUMBER sy - msgno WITH sy - msgv1 sy - msgv2 sy - msgv3 sy - msgv4 .
ENDIF .
ENDIF .
ENDFORM . "lock_record
*------------------------------ 解鎖 -------------------------------------
FORM unlock_record USING p_key .
CALL FUNCTION 'DEQUEUE_EZTESTING'
EXPORTING
mode_ztesting = 'E'
mandt = sy - mandt
zfieldkey = p_key
x_zfieldkey = ' '
_scope = '3'
_synchron = ' '
_collect = ' ' .
ENDFORM. "unlock_record
来源: http://2006057145.blog.163.com/blog/static/1747222022011073723234/