sap 锁 转帖 专题

SAP锁机制

http://blog.chinaunix.net/u2/66669/showart_1687418.html

一、SAP为什么要设置锁:

   1,保持数据的一致性

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

   2,仅仅用Database锁是不够的

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

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

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

二、锁对象和其对应的FM

     在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.

四、上锁的一般步骤

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

****************************************************************

http://blog.youkuaiyun.com/chuangxin/archive/2010/04/11/5473494.aspx

呵呵 想加你做好友啊

类SAP锁机制设计

1.锁的分类:

       1)函数锁(FunctionLock):目的是为了限制函数的并发调用次数,如限制为2,则当该函数已有2人在调用时(尚未调用结束),第3人再去调用时就会报错并且阻断函数的调用,从而减轻服务器负荷;

       2)表锁(TableLock)

2.锁机制

       1)关键字:注册中心(RegisterCenter)、锁队列(LockQueue)、锁控制单元(LockEntry)、锁工厂(LockFactory)、锁(AbstractLock)

    ·注册中心:登记、注销锁的样本特征,主要是锁的应用程序名称和锁名称;

       ·锁队列:锁控制单元入队和出队操作,入队的前提条件是注册中心须有该控制单元的注册记录,出队的扫尾工作是当队列为空时,须在注册中心注销该锁;

       ·锁控制单元:锁控制的最小单元,相当于细胞;

       ·锁工厂:创建锁

       ·锁:执行加锁、解锁、是否已经锁定判断操作
    2)核心类解析:

3)加锁、解锁原理

       由于函数锁和表锁在加锁和解锁操作上执行的具体内容差异很大,因此此处细分为函数锁的加锁和解锁、表锁的加锁和解锁。

a)  函数锁加锁和解锁

加锁:

    ·根据锁工厂LockFactory,传入函数锁类型获取函数锁;
    ·设置锁控制单元LockEntry,主要是application, lockName, maxCount;
·加锁

   伪代码:

LockEntry inEntry = 传入的锁控制单元
LockEntry entry  = 从注册队列获取Entry(inEntry);

If(entry is null){

LockEntry le = 从注册中心获取Entry(inEntry);

If(le is null){

     inEntry.MaxCount = 默认最大值;

     注册中心注册(inEntry);

}else{

     inEntry.MaxCount = le.MaxCount

}

inEntry.AccumlativeCount = inEntry.AccumlativeCount + 1;
注册队列注册(inEntry);

}else{

If(entry.AccumlativeCount> =entry. MaxCount){

     报错,加锁失败,返回错误结果
}else{

    entry.AccumlativeCount ++;

    替换注册队列(entry);
}

}

·解锁

伪代码:

LockEntry inEntry = 传入的锁控制单元
LockEntry entry  = 从注册队列获取Entry(inEntry);

If(entry is null){

    不需解锁,返回结果
}else{

If(entry.AccumlativeCount>1){

     entry.AccumlativeCount --;

替换注册队列(entry);
}else{

    移除注册队列(entry);
}

}

b)  表锁加锁和解锁

加锁:

伪代码:

LockEntry inEntry = 传入的锁控制单元
if(inEngty 没有在注册中心注册){

    注册中心注册(inEntry);

}

list = 获取注册队列();

if(list!=null){

if( inEntry in list){

    报错,返回结果
}else{

    inEntry 入队 list;

    MC中 更新 list

}

}else{

新建队列list, inEntry入队;

MC中 更新 list

}

解锁:

伪代码:

LockEntry inEntry = 传入的锁控制单元
list = 获取注册队列();

if(list==null){

   注册中心注销(inEntry), 返回结果;

}else{

   If(inEntry in list){

       inEntry 出队 list;

       if(list.size()<1){

           MC中移除list;

       }else{

           MC中更新list

       }

   }

}

4)加锁、解锁存在的问题:函数锁存在的问题不大,主要是表锁存在如下问题。

       a)加锁存在的问题:什么时候加锁、锁ID号何时分配

       b)解锁存在的问题:什么时候解锁、该解哪些锁

补充:目前常用的数据并发、一致性方案

1.  所有字段值方法

该方法的核心就是在做Update操作的时候,Where条件匹配所有字段的前后值,该方法的典型运用就是PB。

2.  时间戳(timestamp)法

该方法是目前采用最广发的一种乐观锁定方法,即利用数据库机制,给每张表定义一个timestamp类型字段,然后用户作表的insert、update操作时,数据库会自动更新timestamp字段的值。那么只要用户在更新记录的时候,加上时间戳匹配条件,即可实现乐观锁定。如表timestamp_example(id int pk, code char(3), ts timestamp)

User A: insert(1, ‘001’), 数据库会自动更新timestamp的值,假设为0x000000000001;

User B, User C 同时retrieve得到这条数据(1,’101’, 0x000000000001);

然后,User B更新该数据set code = ‘002’,此时系统会自动更新timestamp,假设更新后为0x000000000002;

此时,User C也想更新这条数据 … set code = ‘003’ where id=1 and tsequal(ts, 0x000000000001),由于ts字段的值已经在User B做更新操作的时候更新掉了,因此User C更新失败,从而实现乐观锁定。

由于,timestamp类型本质上来说是varbinary类型,映射到java数据类型和C#数据类型上是byte[]类型,该类型在数据处理上教int、string等基本类型麻烦得多,而且timestamp受数据库约束较大,因此新平台如欲采用该法来实现数据并发控制的话,将变通如下:

1)  所有数据表增加soaversion int not null字段;

2)  Insert操作时,soaversion赋值1;

3)  Update操作时,set soaversion = (soaversion + 1) % 999999, 如欲控制数据一致性的话,就where 条件加 soaversion = @soaversion

本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/chuangxin/archive/2010/04/11/5473494.aspx

*************************************************************************

简单实现思路:(感谢阿红)


首先在SE11下面建立一个锁对象 



  CALL FUNCTION 'ENQUEUE_EZ_ZTABLENAME'
      EXPORTING
           mode_ZTABLENAME = 'E'
           mandt              = sy-mandt
           KEYFIELD1           = "Value
           KEYFIELD2           = "Value
           KEYFIELD3           = "Value
                   ...
*         X_KEYFIELD1            = ' '
*         X_KEYFIELD2            = ' '
*         X_KEYFIELD3            = ' '
                   ...
*         _SCOPE             = '2'
*         _WAIT              = ' '
*         _COLLECT           = ' '
*   If exceptions are not used, message is displayed within FM
    EXCEPTIONS
         FOREIGN_LOCK       = 1
         SYSTEM_FAILURE     = 2
         OTHERS             = 3.
  IF sy-subrc <> 0.
*   Retrieve message displayed within Function Module
    message id     sy-msgid
              type   'I'
              number sy-msgno
              with   sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    EXIT.
  ENDIF.

下面这个函数是解锁

CALL FUNCTION 'DEQUEUE_EZ_ZTABLENAME'
    EXPORTING
         MODE_ZTABLENAME = 'E'
         MANDT              = SY-MANDT
           mandt              = sy-mandt
           KEYFIELD1           = "Value
           KEYFIELD2           = "Value
           KEYFIELD3           = "Value
                   ...
*         X_KEYFIELD1            = ' '
*         X_KEYFIELD2            = ' '
*         X_KEYFIELD3            = ' '
                   ...
*         _SCOPE             = '3'
*         _SYNCHRON          = ' '
*         _COLLECT           = ' '
          .

那么这个FUNCTION MODUEL是不是要自己写的啊?
完LOCK OBJECT后,自己写FUNCTION MODULE吗?

不用的,就会生成了
到SE37了看

DEQUEUE_*

**************************************

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值