锁机制相关(一)

一、SAP锁的概念

SAP 的锁是一种逻辑锁,SAP为了同步同时多个用户操作同一数据,防止数据出现不一致性而采用了锁机制。一般SAP会在操作数据前设置锁,防止第二个用户进行修改操作,当操作结束后系统在释放锁。

二、SAP为什么要设置锁

1.保持数据的一致性

如果几个用户要访问同样的资源,需要找到一种同步访问的方法去保持数据的一致性。比如说,在航班预订系统中,需要检查还有没有空座位,当检查的时候,你不想别人修改重要的数据(空座位的数量)。

2.仅仅用Database锁是不够的

数据库管理系统物理锁定了要修改的行记录,其他用户要等到数据库锁释放才能访问这个记录。

SAP Lock是一种逻辑锁,相对于DB Lock,是一种轻量级的锁,DB Lock一旦发现不能加锁会进行延迟等待,使用SAP Lock 一定程度上可以减少对DB Lock的占用,避免死锁,同时合理使用SAP Lock可以保证数据的一致性

SAP系统中,当一个新屏幕显示的时候会释放掉Database锁,因为屏幕的改变会触发一个隐式的DB COMMIT。如果数据是从好几个屏幕收集来的话,而且在这段时间内这些数据会分别被锁定,仅仅用Database锁就不够了。

SAP系统在应用服务器层面有一个全局的LOCK TABLE,可以用来设置逻辑锁来锁定相关的表条目,并有ENQUEUE工作进程来管理这些锁。SAP锁是一种逻辑意义上的锁,有可能你锁定的表条目在DATABASE上根本就不存在。

 

注:select for update 是在DB层次上加的锁

三、锁对象和其对应的FM

SE11里创建锁对象,自定义的锁对象都必须以EZ或者EY开头来命名。一个锁对象里只包含一个PRIMARY TABLE,可以包含若干个SECONDARY TABLE,锁的模式有三种:EExclusive lock),SShared lock),XExclusive but not cumulative lock)。LOCK PARAMETERS里填写你要根据哪些字段来锁定表条目。

模式E:当更改数据的时候设置为此模式。

Exclusive lock The locked data can be read or processed by one user only. A request for another exclusive lock or for a shared lock is rejected.

模式S:本身不需要更改数据,但是希望显示的数据不被别人更改。

Shared lock Several users can read the same data at the same time, but as soon as a user edits the data, a second user can no longer access this data. Requests for further shared locks are accepted, even if they are issued by different users, but exclusive locks are rejected.

模式X:和E类似,但是不允许累加,完全独占。

Exclusive but not cumulative lock Exclusive locks can be requested by the same transaction more than once and handled successively, but an exclusive but not cumulative lock can only be requested once by a given transaction. All other lock requests are rejected.

如果你在一个程序里成功对一个锁对象加锁之后,如果模式为E,其他用户不能再对这个锁对象加EXS模式的任意一种锁;

如果你在一个程序里成功对一个锁对象加锁之后,如果模式为X,其他用户不能再对这个锁对象加EXS模式的任意一种锁;

如果你在一个程序里成功对一个锁对象加锁之后,如果模式为S,其他用户不能再对这个锁对象加EX模式的锁,但是可以加S模式的锁;

如果你在一个程序里成功对一个锁对象加锁之后,如果模式为E,在这个程序,你还可以再对这个锁对象加ES模式的锁,X模式的不可以。

如果你在一个程序里成功对一个锁对象加锁之后,如果模式为X,在这个程序,你不可以再对这个锁对象加EXS模式的锁。

如果你在一个程序里成功对一个锁对象加锁之后,如果模式为S,在这个程序,你还可以再对这个锁对象加S模式的锁,如果没有别的用户对其加S模式的锁,那么你还可以对其加E模式的锁。X模式的不可以。

当激活锁对象的时候,系统会自动创建两个FMENQUEUE_<</span>锁对象名>DEQUEUE_<</span>锁对象名>,分别用来锁定和解锁。

四、锁定和解锁

当用逻辑锁来锁定表条目的时候,系统会自动向LOCK TABLE中写入记录。

当调用设置锁的FM时,LOCK PARAMETERS如果没有指明,系统会锁定整个表。当然,LOCK PARAMETERCLIENT有点特殊,如果不指定,默认是SY-MANDT;如果指定相应的CLIENT,会锁定对应CLIENT上的相应的表记录;如果设置为SPACE,则锁定涉及所有的CLIENT

当逻辑锁设置失败后,一般会有两种例外。一个是EXCEPTIONFOREIGN_LOCK,意思是已经被锁定了;另一个是EXCEPTIONSYSTEM_FAILURE

有些情况下,程序中设置成功的逻辑锁会隐式的自己解锁。比如说程序结束发生的时候(MESSAGE TYPEA或者X的时候),使用语句LEAVE PROGRAMLEAVE TO TRANSACTION,或者在命令行输入/n回车以后。

在程序的结束可以用DEQUEUE FUNCTION MODULE来解锁(当然如果你不写这个,程序结束的时候也会自动的解锁),这个时候,系统会自动从LOCK TABLE把相应的记录删除。使用DEQUEUE FUNCTION MODULE来解锁的时候,不会产生EXCEPTION。要解开你在程序中创建的所有的逻辑锁,可以用FMDEQUEUE_ALL.

五、上锁的一般步骤

先上锁,上锁成功之后,从数据库取数据,然后更改数据,接着更新到数据库,最后解锁。按照这个步骤,才能保证更改完全运行在锁的保护机制下。

六、SAP锁的相关知识

1.相关TCODE:SE11

2.相关表

DD25L:组合标题(方式,MC目标,锁定目标)(纪录了锁主表)

DD25T: 视图和锁定对象的短文本

DD26S:视图的基本表和外来码关系(纪录了所有和锁相关的表)

DD27S:合计(视图,MC对象,锁定对象)字段

3.相关函数

RS_DD_ENQU_EDIT

RS_DD_ENQU_ADD

 

4.获取表相关锁的列表程序

REPORT  ZLM_TEST LINE-COUNT 70

                 LINE-SIZE  255

                 NO STANDARD PAGE HEADING.

type-pools: slis.

tables: DD02L,dd26s.

data: begin of g_tab occurs 10,

  TABNAME like dd26s-TABNAME,

  VIEWNAME type dd26s-VIEWNAME,

  ename like EMFIN-FBEMFIN,

  dname like EMFIN-FBEMFIN,

end of g_tab.

data g_fcat  type slis_t_fieldcat_alv.

data:  g_fieldcat type slis_fieldcat_alv.

select-options s_table for dd02l-TABNAME default 'VBAK'.

end-of-selection.

  select dd26s~TABNAME dd25l~VIEWNAME

  INTO CORRESPONDING FIELDS OF TABLE g_tab

  from dd26s

  inner join dd25l

    on dd26s~VIEWNAME = dd25l~VIEWNAME

       and dd25l~AGGTYPE = 'E'

    where TABNAME in s_table.

  loop at g_tab.

    concatenate 'ENQUEUE_' g_tab-VIEWNAME into g_tab-ename.

    concatenate 'DEQUEUE_' g_tab-VIEWNAME into g_tab-dname.

    modify g_tab.

  endloop.

 

  call function 'REUSE_ALV_FIELDCATALOG_MERGE'

    EXPORTING

      i_program_name     = 'ZTEST4'

      I_INTERNAL_TABNAME = 'G_TAB'

      i_inclname         = 'ZTEST4'

    CHANGING

      ct_fieldcat        = g_fcat.

 

  g_fieldcat-fieldname = 'ENAME'.

  g_fieldcat-seltext_s = '加锁函数名'.

  append g_fieldcat to g_fcat.

 

 g_fieldcat-fieldname = 'DNAME'.

  g_fieldcat-seltext_s = '解锁函数名'.

  append  g_fieldcat to g_fcat.

 

  call function 'REUSE_ALV_GRID_DISPLAY'

    exporting

     i_callback_program       = repname

     i_callback_user_command  = g_user_command

     i_structure_name         = 'INV'

     is_layout                = layout

       it_fieldcat              = g_fcat

     is_variant               = g_variant

     it_events                = events[]

     i_callback_pf_status_set = 'F01_ALV_EVENT_PF_STATUS_SET'

    tables

      t_outtab                 = g_tab.

 

5.通过断点找程序所用到的锁

se38打开程序LSENAF01,并定位到send_enqueue子过程,在该过程中的任一语句设置断点。完成断点设置后,则去执行标准tcode,系统就会在程序调用锁时自动停止在断点处,这时你就可以通过调用堆栈获取加锁函数(ENQUEUE_XXXXXX),其中"XXXXXX"就是锁名称,你就可以通过SE11查看锁信息。

 

6 锁相关的函数

DEQUEUE_ALL  Release Locks of an LUW(释放当前LUW的所有锁)

7 如何对表加锁

CALL FUNCTION'ENQUEUE_E_TABLE'

EXPORTING

  MODE_RSTABLE ='E'

  TABNAME ='Table Name'

* VARKEY =

* X_TABNAME = ' '

* X_VARKEY = ' '

* _SCOPE = '2'

* _WAIT = ' '

* _COLLECT = ' '

 EXCEPTIONS

   FOREIGN_LOCK = 1

   SYSTEM_FAILURE = 2

   OTHERS = 3

          .

IF sy-subrc = 0.

 WRITE: 'Lock table successfully!'.

 else.

  write: 'Failed'.

ENDIF.

 

七、锁对象(Lock Object)和 FMFunction Module
激活锁定对象时,产生的 FM 的名字是什么?

答案:首先要在 ABAP 字典中创建锁对象,然后才能在 ABAP 程序中设锁。创建锁对象时,系统会自动生成两个 FM 来进行锁管理。

用于设锁的 FM 为: ENQUEUE_<</span>锁对象名>。它用于在锁表(Lock Table)中生成一个锁项(Lock Entry)。若设锁不成功的话,就会在 Return 中反映出来。

用于释放锁的 FM 为:DEQUEUE_<</span>锁对象名>。它用于从锁表中删除一个锁项。在 ABAP 程序中,只需使用 "CALL FUNCITION ..." 语句就可以调用它们。这两个锁 FM 是在 SAP 系统的一个特殊工作进程中执行的,专门进行锁管理。它运行在一个单独的服务器上,而该服务器专门用于维护整个 SAP 系统的主锁表(Central Locak Table)。

八、加锁和解锁FM的一些参数

scope 参数: 1 表示程序内有效, 2 表示 update module 内有效, 3 表示全部有效。

_wait 表示如果对象已经被锁定,是否等待后再尝试加锁,最大的等待时间 有系统参数 ENQUE/DELAY_MAX控制。

_COLLECT 参数表示是否收集后进行统一提交,COLLECT 是一种缓存与批处理方法,即如果指定了Collect,加锁信息会放到Lock Container,Lock Container实际上是一个funciton Group控制的内存区域,如果程序中加了很多锁,锁信息会先放到内存中,这样可以减少对SAP锁管理系统访问,若使Lock Container中的锁生效,需执行FLUSH_ENQUEUE 这个Funciton,将锁信息更新到锁管理系统中,此时加锁操作生效,使用函数RESET_ENQUEUE可以清除Lock Container中的锁信息。

释放锁:调用DEQUEUE函数

如果程序更新用到到V1 Update,commit work是会删除所有的锁


最后关于加锁时
scope 参数:1 2 3特做测试后的补充。

对于最终的效果,scope = 1 和 scope = 3是一样的。
    在调用加锁函数时,锁加上,SM12可查到。

中间无论是调用其他FM,还是调用BAPI,及时使用了commit work。

锁依然存在,SM12一直可以查,

直到调用了解锁函数,锁才能解掉,【在SM12里消失】。


如果 scope = 2.

如果加锁后,使用了 in up date task 模式调用了FUNCUNTION 。

则锁就进入了更新进程里【目前执行程序在dialog进程里】

如果调用FM后,使用了commit work。
    则锁自动解【SM内消失】


但是!

如果 scope = 2.

就是正常的dialog或者Report,中间没有调用 in up date task模式【或同等效果的】

则此锁还在dialog进程里。

commit work不会解锁

只有调用解锁函数才能结。


综上:调用的时候就是用scope = 1

防止调用过程中意外解锁,导致数据不一致。

 


posted @ 2014-01-22 09:24  胡来  阅读(181)  评论(0编辑  收藏  举报