Enqueue Lock in Netweaver as JAVA

本文地址:https://flexibility.github.io/MD/SAP/Java/01-Enqueue-Lock-in-NW-as-JAVA

[TOC]

參考

SAP Help Portal : Developing Java EE 5 Applications/Task/Developing Persistence/Locks

概念

鎖和事務(wù)隔離

鎖的概念和 事務(wù)隔離( transaction isolation )相關(guān)荞膘。

事務(wù)隔離 是為了規(guī)避多個并發(fā)(simultaneously running)的事務(wù)不被相互影響疟暖。隔離的級別通過對數(shù)據(jù)庫表的行的讀和改的鎖定來實現(xiàn)

鎖定機制

有以下兩種鎖定機制:

  1. Database locks。通過數(shù)據(jù)庫提供的鎖機制來實現(xiàn)钠右,缺點是不同的數(shù)據(jù)庫對鎖的語義(semantics)沒有統(tǒng)一標(biāo)準(zhǔn)舌界。
  2. Logical locks掘譬。鎖定機制由NW as Java提供和集中管理( Enqueue Server 通過集中的lock table進(jìn)行管理)。
    J2EE應(yīng)用使用由 Locking Adapter Service 提供的LogicalLockingTableLocking接口來訪問 Locking Manager 來和 Enqueue Server 進(jìn)行通信

Enqueue Server

Enqueue Server 不和持久層存儲介質(zhì)( persistent storage )交互呻拌,如DB葱轩,文件系統(tǒng)等;只和主存中的 central lock table 進(jìn)行通信
每一次鎖定請求就有一次應(yīng)用和 Enqueue Server 之間的通信。合適的 鎖定粒度(granularity)可以減少網(wǎng)絡(luò)通信靴拱,比如使用通配符(wildcard character)來鎖定范圍數(shù)據(jù)垃喊。

read/write/shared/exclusive locks

使用邏輯鎖可以鎖定單行數(shù)據(jù)或者區(qū)域數(shù)據(jù)。分為讀鎖(write locks)和 寫鎖(write locks)袜炕。

對于一個對象本谜,最多可以存在一個寫鎖讀鎖 可以存在多個偎窘。寫鎖讀鎖 是互斥(mutually exclusive)的乌助。

因此,讀鎖 也叫 共享鎖(shared locks), 寫鎖 也叫 排他鎖(exclusive locks)

Enqueue Locks Guidelines

Enqueue Locks Guidelines

  • Enqueue locking applies both to the SAP NetWeaver AS for Java system database and external databases supported by SAP NetWeaver AS for Java.
  • All application components must rely on enqueue locking. Locking works if all components rely on the same locking principle.
  • All application components must commit to apply the same locking protocol.
  • With enqueue locking, JDBC data sources must operate on the lowest, READ_UNCOMMITTED transaction isolation level.
  • Enqueue locking works with Open SQL, Native SQL, and Vendor SQL.
  • To obtain an enqueue lock, you must have an active JTA or database transaction
  • We recommend that you choose and use one persistence API consistently:

    With ORM technologies such as EJB CMP and JDO, you do not need to set locks explicitly. Both frameworks implicitly lock persistent objects by default.

    In all other cases, you set and release enqueue locks using the interfaces of the Application Locking Service:
    • To lock specific database items you use the TableLocking API.
    • In all other cases, you use the LogicalLocking API.
  • We recommend that you set locks only when necessary and for as short a time as possible. To release locks you use one of the following approaches:
    • To release locks in the application, you use the dedicated methods of the TableLocking and LogicalLocking APIs.
    • Locks exist within the scope of a transaction. When a transaction ends, the AS Java automatically releases the locks set during the transaction.
  • To manage, test, and view statistics about enqueue locks, you use the Application Locking Service.

More information: Managing Locks

使用

準(zhǔn)備

  • Design time:需要訪問以下庫 applocking.jar陌知,frame.jar他托,exception.jar(根本沒用,后面會有說明)

然而實際使用的時候發(fā)現(xiàn)未找到frame.jar仆葡,applocking.jar之間報過時赏参,exception.jar增加了命名空間,變成了com.sap.exception沿盅。
代碼根本編譯不了登刺,然后看了下700~750的文檔,發(fā)現(xiàn)這塊的文檔基本都沒變過嗡呼,還是這幾個lib,估計基本都放棄更新文檔了皇耗,畢竟南窗。。郎楼。

經(jīng)過不停的嘗試万伤,最終發(fā)現(xiàn) tc/je/locking/apitc/bl/exception/lib 這兩個service對dc可以。

DC依賴

DC

jar包

jar包

API

APIs

TableLocking API
public void lock(
    byte lifetime, 
    Connection connection, 
    String tableName, 
    Map primaryKeys, 
    char mode
) 
throws  LockException, 
        TechnicalLockException,
        IllegalArgumentException;
  • lifetime : 生命周期
  • connection : 數(shù)據(jù)庫連接
  • tableName : 表名
  • primaryKeys : 主鍵(可用通配符)
  • mode : 鎖模式
LogicalLocking API
public void lock(
    byte lifetime,
    java.lang.String name,
    java.lang.String argument,
    char mode,
    int timeout
)
throws  com.sap.engine.frame.core.locking.LockException,
        com.sap.engine.frame.core.locking.TechnicalLockException,
        java.lang.IllegalArgumentException;
  • lifetime : 生命周期
  • name : 鎖名( 必須以所屬的namespace開頭
  • argument : 鎖參數(shù)
  • mode : 鎖模式
  • timeout : 加鎖沖突等待超時時間(ms)

參數(shù)

  • LIFETIME | 生命周期

    • TableLocking.LIFETIME_USERSESSION : 基于用戶session呜袁,若不顯式unlock會一直持續(xù)到session結(jié)束
    • TableLocking.LIFETIME_TRANSACTION : 推薦方式敌买。依賴事務(wù),必須激活JTA或者數(shù)據(jù)庫事務(wù)阶界,若不顯式unlock會在事務(wù)結(jié)束(commit|rollback)后自動釋放
  • MODE | 鎖模式

    • TableLocking.MODE_SHARED : 共享鎖(S Lock)
    • TableLocking.MODE_EXCLUSIVE_CUMULATIVE : 累積互斥鎖(E Lock)虹钮,同一個transaction中可以累積加鎖。
    • TableLocking.MODE_EXCLUSIVE_NONCUMULATIVE : 非累積互斥鎖(X Lock)膘融,任何時候只能鎖定一次
    • *TableLocking.MODE_OPTIMISTIC* : 樂觀鎖(O Lock)
      與S lock類似芙粱,可以與S lock/O lock共存,與E lock/X lock互斥氧映。
      與S lock最大區(qū)別:O lock 可以升級到R lock春畔,當(dāng)一個O lock升到R lock,其他O lock會失效
    • *TableLocking.MODE_OPTIMISTIC_TO_EXCLUSIVE* : 樂觀鎖升級互斥鎖(R Lock)。
      必須保證存在樂觀鎖律姨,否則會報錯 "the lock propagation failed, because the optimistic lock is gone"
    • *TableLocking.MODE_CHECK_SHARED* : 只check不占用
    • *TableLocking.MODE_CHECK_EXCLUSIVE_CUMULATIVE* : 只check不占用
    • *TableLocking.MODE_CHECK_EXCLUSIVE_NONCUMULATIVE* : 只check不占用
  • 通配符

    • TableLocking.WILDCARD_CHARACTER_SINGLE : 代表1個字符
    • TableLocking.WILDCARD_CHARACTER_MULTI : 代表多個字符

DEMO(LogicalLock)

package flex.test.rest;

import java.sql.Connection;
import java.util.Map;

import javax.naming.InitialContext;
import javax.transaction.UserTransaction;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

import afce.base.ejb.common.type.FlexMap;
import afce.base.ejb.util.DBUtil;

import com.ibm.basis.sqldao.executor.DBConnection;
import com.sap.engine.frame.core.locking.LockException;
import com.sap.engine.services.applocking.LogicalLocking;
import com.sap.engine.services.applocking.LogicalLockingFactory;


@Path("/query")
public class TestRestCFG {

    @GET
    @Path("/lock")
    @Produces("application/json;charset=utf-8")
    public Map<String,Object> test(
            @DefaultValue("test01") @QueryParam("name") String p_lock_name,
            @DefaultValue("E") @QueryParam("mode") String p_lock_mode,
            @DefaultValue("1000") @QueryParam("timeout") int p_lock_timeout,
            @DefaultValue("30") @QueryParam("during") int p_lock_during
    ){
        
        char c_lock_mode = (p_lock_mode==null||p_lock_mode.length()<1)?'E':p_lock_mode.charAt(0);
//      E - LogicalLocking.MODE_EXCLUSIVE_CUMULATIVE
//      X - LogicalLocking.MODE_EXCLUSIVE_NONCUMULATIVE
//      S - LogicalLocking.MODE_SHARED
//      O - LogicalLocking.MODE_OPTIMISTIC
//      R - LogicalLocking.MODE_OPTIMISTIC_TO_EXCLUSIVE
        
        FlexMap<String, Object> oret = FlexMap.SO();
        
        String lock_NS = "Flex.lock";
        String lock_name = lock_NS + "." + p_lock_name;
        String lock_para = "flex01";

        
        UserTransaction ut = null;
        Connection conn = null;
        try {

            conn = DBConnection.getConnection();
            ut = DBUtil.getUT(conn);
            ut.begin();
        
        InitialContext ctx = new InitialContext();
            LogicalLockingFactory lf = (LogicalLockingFactory) ctx.lookup(LogicalLockingFactory.JNDI_NAME);
            LogicalLocking ll = lf.createLogicalLocking(lock_NS, "Flex Lock NS");
            oret.put("before lock", "------"+new java.util.Date().toString());
            oret.put("LOCK_NAME", lock_name)
                    .put("LOCK_PARA", lock_para)
                    .put("LOCK_MODE", p_lock_mode)
                    .put("LOCK_TIMEOUT", p_lock_timeout)
                    .put("LOCK_DURING", p_lock_during)
                    ;

            ll.lock(
                    LogicalLocking.LIFETIME_TRANSACTION, 
                    lock_name, lock_para, 
//                  LogicalLocking.MODE_EXCLUSIVE_CUMULATIVE
                    c_lock_mode
                    ,p_lock_timeout
            );

            oret.put("after lock", "------"+new java.util.Date().toString());
            try {java.util.concurrent.TimeUnit.SECONDS.sleep(p_lock_during);}
            catch (InterruptedException e) {e.printStackTrace();}
            oret.put("last", "------"+new java.util.Date().toString());

        }
        catch (LockException e) {
            oret.put("exception", 
                    "請求的鎖對象<"+lock_name+">"+"正在被【"+
                    e.getCollisionUserName()+
                    "】鎖定!"+
                    "("+lock_para+")"
            );
            oret.put("exception-msg",e.getMessage()); 
        }
        catch (Exception e) {
            oret.put("exception", e.getMessage()+new java.util.Date().toString());
        }
        finally{DBConnection.freeConnection(conn);}
        
        return oret.o();
    }
    
}

提供了rest服務(wù)進(jìn)行鎖定振峻,如果鎖定成功,將會占用30秒择份,如果未占用成功則直接返回報錯信息.
*https://IP端口/應(yīng)用/rest/query/lock?name=flex&mode=E&timeout=0&during=30

測試的時候扣孟,如果在一個session的瀏覽器環(huán)境需要加參數(shù)來區(qū)分連接,不清楚原因缓淹,否則將會出現(xiàn)串行處理請求的情況哈打,無法模擬并發(fā)鎖的場景

可以增加參數(shù)來區(qū)分連接:

  • 服務(wù)路徑/rest/query/lock?name=flex&mode=E&timeout=0&during=30
  • 服務(wù)路徑/rest/query/lock?name=flex&mode=E&timeout=0&during=30&_r=2

測試截圖:
打開2個互斥鎖


測試截圖1

打開3個共享鎖后打開1個互斥鎖


測試截圖2
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市讯壶,隨后出現(xiàn)的幾起案子料仗,更是在濱河造成了極大的恐慌,老刑警劉巖伏蚊,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件立轧,死亡現(xiàn)場離奇詭異,居然都是意外死亡躏吊,警方通過查閱死者的電腦和手機氛改,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來比伏,“玉大人胜卤,你說我怎么就攤上這事×尴睿” “怎么了葛躏?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長悠菜。 經(jīng)常有香客問我舰攒,道長,這世上最難降的妖魔是什么悔醋? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任摩窃,我火速辦了婚禮,結(jié)果婚禮上芬骄,老公的妹妹穿的比我還像新娘猾愿。我一直安慰自己,他們只是感情好德玫,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布匪蟀。 她就那樣靜靜地躺著,像睡著了一般宰僧。 火紅的嫁衣襯著肌膚如雪材彪。 梳的紋絲不亂的頭發(fā)上观挎,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機與錄音段化,去河邊找鬼嘁捷。 笑死,一個胖子當(dāng)著我的面吹牛显熏,可吹牛的內(nèi)容都是我干的雄嚣。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼喘蟆,長吁一口氣:“原來是場噩夢啊……” “哼缓升!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蕴轨,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤港谊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后橙弱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體歧寺,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年棘脐,在試婚紗的時候發(fā)現(xiàn)自己被綠了斜筐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡蛀缝,死狀恐怖顷链,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情屈梁,我是刑警寧澤蕴潦,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站俘闯,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏忽冻。R本人自食惡果不足惜真朗,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望僧诚。 院中可真熱鬧遮婶,春花似錦、人聲如沸湖笨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽慈省。三九已至臀防,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背袱衷。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工捎废, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人致燥。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓登疗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親嫌蚤。 傳聞我的和親對象是個殘疾皇子辐益,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355