66_數(shù)據(jù)建模實戰(zhàn)_基于共享鎖和排他鎖實現(xiàn)悲觀鎖并發(fā)控制

<meta charset="utf-8">

66_數(shù)據(jù)建模實戰(zhàn)_基于共享鎖和排他鎖實現(xiàn)悲觀鎖并發(fā)控制

1、共享鎖和排他鎖的說明

共享鎖:這份數(shù)據(jù)是共享的,然后多個線程過來,都可以獲取同一個數(shù)據(jù)的共享鎖,然后對這個數(shù)據(jù)執(zhí)行讀操作

排他鎖:是排他的操作,只能一個線程獲取排他鎖,然后執(zhí)行增刪改操作

讀寫鎖的分離

如果只是要讀取數(shù)據(jù)的話,那么任意個線程都可以同時進來然后讀取數(shù)據(jù),每個線程都可以上一個共享鎖

但是這個時候,如果有線程要過來修改數(shù)據(jù),那么會嘗試上排他鎖,排他鎖會跟共享鎖互斥,也就是說,如果有人已經(jīng)上了共享鎖了,那么排他鎖就不能上,就得等

如果有人在讀數(shù)據(jù),就不允許別人來修改數(shù)據(jù)

反之,也是一樣的

如果有人在修改數(shù)據(jù),就是加了排他鎖

那么其他線程過來要修改數(shù)據(jù),也會嘗試加排他鎖,此時會失敗,鎖沖突,必須等待,同時只能有一個線程修改數(shù)據(jù)

如果有人過來同時要讀取數(shù)據(jù),那么會嘗試加共享鎖,此時會失敗,因為共享鎖和排他鎖是沖突的

如果有在修改數(shù)據(jù),就不允許別人來修改數(shù)據(jù),也不允許別人來讀取數(shù)據(jù)

2、共享鎖和排他鎖的實驗

第一步:有人在讀數(shù)據(jù),其他人也能過來讀數(shù)據(jù)

創(chuàng)建一個groovy文件,寫入如下script語法,即排他鎖報錯,共享鎖+1

judge-lock-2.groovy: if (ctx._source.lock_type == 'exclusive') { assert false }; ctx._source.lock_count++

image.png

上一個共享鎖

POST /fs/lock/1/_update { "upsert": { "lock_type": "shared", "lock_count": 1 }, "script": { "lang": "groovy", "file": "judge-lock-2" } }

繼續(xù)加一個共享鎖,發(fā)現(xiàn)是可以讀的

POST /fs/lock/1/_update { "upsert": { "lock_type": "shared", "lock_count": 1 }, "script": { "lang": "groovy", "file": "judge-lock-2" } }

獲取鎖信息

GET /fs/lock/1

{

"_index": "fs",

"_type": "lock",

"_id": "1",

"_version": 3,

"found": true,

"_source": {

"lock_type": "shared",

"lock_count": 3

}

}

就給大家模擬了,有人上了共享鎖,你還是要上共享鎖,直接上就行了,沒問題,只是lock_count加1

第二步:已經(jīng)有人上了共享鎖,然后有人要上排他鎖

PUT /fs/lock/1/_create { "lock_type": "exclusive" }

排他鎖用的不是upsert語法,create語法,要求lock必須不能存在,直接自己是第一個上鎖的人,上的是排他鎖

{

"error": {

"root_cause": [

{

"type": "version_conflict_engine_exception",

"reason": "[lock][1]: version conflict, document already exists (current version [3])",

"index_uuid": "IYbj0OLGQHmMUpLfbhD4Hw",

"shard": "3",

"index": "fs"

}

],

"type": "version_conflict_engine_exception",

"reason": "[lock][1]: version conflict, document already exists (current version [3])",

"index_uuid": "IYbj0OLGQHmMUpLfbhD4Hw",

"shard": "3",

"index": "fs"

},

"status": 409

}

如果已經(jīng)有人上了共享鎖,明顯/fs/lock/1是存在的,create語法去上排他鎖,肯定會報錯

第三步: 對共享鎖進行解鎖

創(chuàng)建解鎖groovy文件

image.png
image.png

解鎖語法:

POST /fs/lock/1/_update { "script": { "lang": "groovy", "file": "unlock-shared" } }

連續(xù)解鎖3次,此時共享鎖就徹底沒了

每次解鎖一個共享鎖,就對lock_count先減1,如果減了1之后,是0,那么說明所有的共享鎖都解鎖完了,此時就就將/fs/lock/1刪除,就徹底解鎖所有的共享鎖

第四步: 上排他鎖,再上排他鎖

PUT /fs/lock/1/_create { "lock_type": "exclusive" }

其他線程

PUT /fs/lock/1/_create { "lock_type": "exclusive" }

肯定產(chǎn)生沖突,報錯

{

"error": {

"root_cause": [

{

"type": "version_conflict_engine_exception",

"reason": "[lock][1]: version conflict, document already exists (current version [7])",

"index_uuid": "IYbj0OLGQHmMUpLfbhD4Hw",

"shard": "3",

"index": "fs"

}

],

"type": "version_conflict_engine_exception",

"reason": "[lock][1]: version conflict, document already exists (current version [7])",

"index_uuid": "IYbj0OLGQHmMUpLfbhD4Hw",

"shard": "3",

"index": "fs"

},

"status": 409

}

第五步:、上排他鎖,上共享鎖

排他鎖之后再上共享鎖,報錯

POST /fs/lock/1/_update { "upsert": { "lock_type": "shared", "lock_count": 1 }, "script": { "lang": "groovy", "file": "judge-lock-2" } }

報錯信息如下:

{

"error": {

"root_cause": [

{

"type": "remote_transport_exception",

"reason": "[4onsTYV][127.0.0.1:9300][indices:data/write/update[s]]"

}

],

"type": "illegal_argument_exception",

"reason": "failed to execute script",

"caused_by": {

"type": "script_exception",

"reason": "error evaluating judge-lock-2",

"caused_by": {

"type": "power_assertion_error",

"reason": "assert false\n"

},

"script_stack": [],

"script": "",

"lang": "groovy"

}

},

"status": 400

}

第六步:解鎖排他鎖

DELETE /fs/lock/1

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容