日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

休眠锁定模式– PESSIMISTIC_READ和PESSIMISTIC_WRITE如何工作

發(fā)布時(shí)間:2023/12/3 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 休眠锁定模式– PESSIMISTIC_READ和PESSIMISTIC_WRITE如何工作 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

介紹

Java Persistence API帶有完善的并發(fā)控制機(jī)制,支持隱式和顯式鎖定。 隱式鎖定機(jī)制很簡單,它依賴于:

  • 樂觀鎖定:實(shí)體狀態(tài)更改可以觸發(fā)版本增加
  • 行級(jí)鎖定:基于當(dāng)前運(yùn)行的事務(wù)隔離級(jí)別 ,INSERT / UPDATE / DELETE語句可能會(huì)獲取排他行鎖

雖然隱式鎖定適用于許多情況,但顯式鎖定機(jī)制可以利用更細(xì)粒度的并發(fā)控制。

在以前的文章中,我介紹了顯式的樂觀鎖定模式:

  • 樂觀的
  • OPTIMISTIC_FORCE_INCREMENT
  • PESSIMISTIC_FORCE_INCREMENT

在這篇文章中,我將解開顯式的悲觀鎖模式:

  • PESSIMISTIC_READ
  • PESSIMISTIC_WRITE

讀寫器鎖

數(shù)據(jù)庫系統(tǒng)是高度并發(fā)的環(huán)境,因此許多并發(fā)理論習(xí)慣用法也適用于數(shù)據(jù)庫訪問。 必須將并發(fā)更改序列化以保留數(shù)據(jù)完整性,因此,即使通常通過Multiversion并發(fā)控制機(jī)制對(duì)其進(jìn)行補(bǔ)充,大多數(shù)數(shù)據(jù)庫系統(tǒng)仍使用兩階段鎖定策略。

因?yàn)榛コ怄i定會(huì)阻礙可伸縮性(平等地處理讀寫),所以大多數(shù)數(shù)據(jù)庫系統(tǒng)都使用讀寫器鎖定同步方案,因此:

  • 共享(讀取)鎖會(huì)阻止作者,從而允許多個(gè)讀者繼續(xù)
  • 排他(寫入)鎖同時(shí)阻止讀取器和寫入器,從而使所有寫入操作都按順序應(yīng)用

因?yàn)殒i定語法不是SQL標(biāo)準(zhǔn)的一部分,所以每個(gè)RDBMS都選擇了不同的語法:

數(shù)據(jù)庫名稱 共享鎖語句 排他鎖聲明
甲骨文 更新 更新
的MySQL 鎖定共享模式 更新
Microsoft SQL服務(wù)器 帶(HOLDLOCK,ROWLOCK) 帶(上鎖,上鎖)
PostgreSQL的 分享 更新
DB2 只供RS閱讀 用于RS更新

Java持久性抽象層隱藏了特定于數(shù)據(jù)庫的鎖定語義,提供了僅需要兩個(gè)鎖定模式的通用API。 使用PESSIMISTIC_READ鎖定模式類型獲取共享/讀取鎖定,而使用PESSIMISTIC_WRITE請(qǐng)求排他/寫入鎖定。

PostgreSQL行級(jí)鎖定模式

對(duì)于下一個(gè)測試用例,我們將使用PostgreSQL,因?yàn)樗戎С知?dú)占鎖定 ,也支持共享顯式鎖定 。

以下所有測試將使用相同的并發(fā)實(shí)用程序,模擬兩個(gè)用戶:Alice和Bob。 每個(gè)測試方案將驗(yàn)證特定的讀/寫鎖定組合。

private void testPessimisticLocking(ProductLockRequestCallable primaryLockRequestCallable, ProductLockRequestCallable secondaryLockRequestCallable) {doInTransaction(session -> {try {Product product = (Product) session.get(Product.class, 1L);primaryLockRequestCallable.lock(session, product);executeAsync(() -> {doInTransaction(_session -> {Product _product = (Product) _session.get(Product.class, 1L);secondaryLockRequestCallable.lock(_session, _product);});},endLatch::countDown);sleep(WAIT_MILLIS);} catch (StaleObjectStateException e) {LOGGER.info("Optimistic locking failure: ", e);}});awaitOnLatch(endLatch); }

情況1:PESSIMISTIC_READ不阻止PESSIMISTIC_READ鎖定請(qǐng)求

第一個(gè)測試將檢查兩個(gè)并發(fā)的PESSIMISTIC_READ鎖定請(qǐng)求如何交互:

@Test public void testPessimisticReadDoesNotBlockPessimisticRead() throws InterruptedException {LOGGER.info("Test PESSIMISTIC_READ doesn't block PESSIMISTIC_READ");testPessimisticLocking((session, product) -> {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_READ)).lock(product);LOGGER.info("PESSIMISTIC_READ acquired");},(session, product) -> {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_READ)).lock(product);LOGGER.info("PESSIMISTIC_READ acquired");}); }

運(yùn)行此測試,我們得到以下輸出:

[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Test PESSIMISTIC_READ doesn't block PESSIMISTIC_READ#Alice selects the Product entity [Alice]: Time:1 Query:{[ SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_ FROM product lockmodepe0_ WHERE lockmodepe0_.id = ? ][1]} #Alice acquires a SHARED lock on the Product entity [Alice]: Time:1 Query:{[ SELECT id FROM product WHERE id =? AND version =? FOR share ][1,0]} [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_READ acquired#Alice waits for 500ms [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Wait 500 ms!#Bob selects the Product entity [Bob]: Time:1 Query:{[SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_ FROM product lockmodepe0_ WHERE lockmodepe0_.id = ? ][1]}#Bob acquires a SHARED lock on the Product entity [Bob]: Time:1 Query:{[ SELECT id FROM product WHERE id =? AND version =? FOR share ][1,0]} [Bob]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_READ acquired#Bob's transactions is committed [Bob]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection#Alice's transactions is committed [Alice]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection

在這種情況下,沒有任何爭用。 愛麗絲和鮑勃都可以獲取共享鎖,而不會(huì)遇到任何沖突。

情況2:PESSIMISTIC_READ阻止UPDATE隱式鎖定請(qǐng)求

第二種情況將演示共享鎖如何防止并發(fā)修改。 愛麗絲將獲得一個(gè)共享鎖,而鮑勃將嘗試修改該鎖定的實(shí)體:

@Test public void testPessimisticReadBlocksUpdate() throws InterruptedException {LOGGER.info("Test PESSIMISTIC_READ blocks UPDATE");testPessimisticLocking((session, product) -> {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_READ)).lock(product);LOGGER.info("PESSIMISTIC_READ acquired");},(session, product) -> {product.setDescription("USB Flash Memory Stick");session.flush();LOGGER.info("Implicit lock acquired");}); }

測試生成以下輸出:

[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Test PESSIMISTIC_READ blocks UPDATE#Alice selects the Product entity [Alice]: Time:0 Query:{[ SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_ FROM product lockmodepe0_ WHERE lockmodepe0_.id = ? ][1]} #Alice acquires a SHARED lock on the Product entity [Alice]: Time:0 Query:{[ SELECT id FROM product WHERE id =? AND version =? FOR share ][1,0]} [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_READ acquired#Alice waits for 500ms [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Wait 500 ms!#Bob selects the Product entity [Bob]: Time:1 Query:{[ SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_ FROM product lockmodepe0_ WHERE lockmodepe0_.id = ? ][1]} #Alice's transactions is committed [Alice]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection#Bob can acquire the Product entity lock, only after Alice's transaction is committed [Bob]: Time:427 Query:{[ UPDATE product SET description = ?,price = ?,version = ? WHERE id = ?AND version = ? ][USB Flash Memory Stick,12.99,1,1,0]} [Bob]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Implicit lock acquired#Bob's transactions is committed [Bob]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection

盡管Bob可以選擇Product實(shí)體,但UPDATE會(huì)一直延遲到提交Alice事務(wù)為止(這就是UPDATE花費(fèi)427ms運(yùn)行的原因)。

情況3:PESSIMISTIC_READ阻止PESSIMISTIC_WRITE鎖定請(qǐng)求

輔助PESSIMISTIC_WRITE鎖定請(qǐng)求也表現(xiàn)出相同的行為:

@Test public void testPessimisticReadBlocksPessimisticWrite() throws InterruptedException {LOGGER.info("Test PESSIMISTIC_READ blocks PESSIMISTIC_WRITE");testPessimisticLocking((session, product) -> {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_READ)).lock(product);LOGGER.info("PESSIMISTIC_READ acquired");},(session, product) -> {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_WRITE)).lock(product);LOGGER.info("PESSIMISTIC_WRITE acquired");}); }

提供以下輸出:

[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Test PESSIMISTIC_READ blocks PESSIMISTIC_WRITE#Alice selects the Product entity [Alice]: Time:0 Query:{[ SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_ FROM product lockmodepe0_ WHERE lockmodepe0_.id = ? ][1]}#Alice acquires a SHARED lock on the Product entity [Alice]: Time:1 Query:{[ SELECT id FROM product WHERE id =? AND version =? FOR share ][1,0]} [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_READ acquired#Alice waits for 500ms [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Wait 500 ms!#Bob selects the Product entity [Bob]: Time:1 Query:{[ SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_ FROM product lockmodepe0_ WHERE lockmodepe0_.id = ? ][1]} #Alice's transactions is committed [Alice]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection#Bob can acquire the Product entity lock, only after Alice's transaction is committed [Bob]: Time:428 Query:{[ SELECT id FROM product WHERE id = ?AND version = ? FOR UPDATE ][1,0]} [Bob]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_WRITE acquired#Bob's transactions is committed [Bob]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection

Bob的排他鎖請(qǐng)求等待Alice的共享鎖被釋放。

情況4:PESSIMISTIC_READ阻止PESSIMISTIC_WRITE鎖定請(qǐng)求,NO WAIT快速失敗

Hibernate提供了一個(gè)PESSIMISTIC_NO_WAIT超時(shí)指令,該指令轉(zhuǎn)換為特定于數(shù)據(jù)庫的NO_WAIT鎖獲取策略。

PostgreSQL NO WAIT指令描述如下:

為防止該操作等待其他事務(wù)提交,請(qǐng)使用NOWAIT選項(xiàng)。 使用NOWAIT,如果無法立即鎖定選定的行,該語句將報(bào)告錯(cuò)誤,而不是等待。 注意,NOWAIT僅適用于行級(jí)鎖-所需的ROW SHARE表級(jí)鎖仍以常規(guī)方式獲取(請(qǐng)參見第13章)。 如果需要不等待就獲取表級(jí)鎖,則可以先將LOCK與NOWAIT選項(xiàng)一起使用。

@Test public void testPessimisticReadWithPessimisticWriteNoWait() throws InterruptedException {LOGGER.info("Test PESSIMISTIC_READ blocks PESSIMISTIC_WRITE, NO WAIT fails fast");testPessimisticLocking((session, product) -> {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_READ)).lock(product);LOGGER.info("PESSIMISTIC_READ acquired");},(session, product) -> {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_WRITE)).setTimeOut(Session.LockRequest.PESSIMISTIC_NO_WAIT).lock(product);LOGGER.info("PESSIMISTIC_WRITE acquired");}); }

該測試生成以下輸出:

[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Test PESSIMISTIC_READ blocks PESSIMISTIC_WRITE, NO WAIT fails fast#Alice selects the Product entity [Alice]: Time:1 Query:{[ SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_ FROM product lockmodepe0_ WHERE lockmodepe0_.id = ? ][1]}#Alice acquires a SHARED lock on the Product entity [Alice]: Time:1 Query:{[ SELECT id FROM product WHERE id =? AND version =? FOR share ][1,0]} [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_READ acquired#Alice waits for 500ms [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Wait 500 ms!#Bob selects the Product entity [Bob]: Time:1 Query:{[ SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_ FROM product lockmodepe0_ WHERE lockmodepe0_.id = ? ][1]}#Bob tries to acquire an EXCLUSIVE lock on the Product entity and fails because of the NO WAIT policy [Bob]: Time:0 Query:{[ SELECT id FROM product WHERE id = ?AND version = ? FOR UPDATE nowait ][1,0]} [Bob]: o.h.e.j.s.SqlExceptionHelper - SQL Error: 0, SQLState: 55P03 [Bob]: o.h.e.j.s.SqlExceptionHelper - ERROR: could not obtain lock on row in relation "product"#Bob's transactions is rolled back [Bob]: o.h.e.t.i.j.JdbcTransaction - rolled JDBC Connection#Alice's transactions is committed [Alice]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection

由于Alice已經(jīng)在與產(chǎn)品實(shí)體相關(guān)聯(lián)的數(shù)據(jù)庫行上持有共享鎖,因此Bob的排他鎖請(qǐng)求立即失敗。

情況5:PESSIMISTIC_WRITE阻止PESSIMISTIC_READ鎖定請(qǐng)求

下一個(gè)測試證明排他鎖將始終阻止共享鎖獲取嘗試:

@Test public void testPessimisticWriteBlocksPessimisticRead() throws InterruptedException {LOGGER.info("Test PESSIMISTIC_WRITE blocks PESSIMISTIC_READ");testPessimisticLocking((session, product) -> {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_WRITE)).lock(product);LOGGER.info("PESSIMISTIC_WRITE acquired");},(session, product) -> {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_READ)).lock(product);LOGGER.info("PESSIMISTIC_WRITE acquired");}); }

生成以下輸出:

[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Test PESSIMISTIC_WRITE blocks PESSIMISTIC_READ#Alice selects the Product entity [Alice]: Time:1 Query:{[ SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_ FROM product lockmodepe0_ WHERE lockmodepe0_.id = ? ][1]} #Alice acquires an EXCLUSIVE lock on the Product entity [Alice]: Time:0 Query:{[ SELECT id FROM product WHERE id = ?AND version = ? FOR UPDATE ][1,0]} [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_WRITE acquired#Alice waits for 500ms [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Wait 500 ms!#Bob selects the Product entity [Bob]: Time:1 Query:{[ SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_ FROM product lockmodepe0_ WHERE lockmodepe0_.id = ? ][1]}#Alice's transactions is committed [Alice]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection#Bob can acquire the Product entity SHARED lock, only after Alice's transaction is committed [Bob]: Time:428 Query:{[ SELECT id FROM product WHERE id =? AND version =? FOR share ][1,0]} [Bob]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_WRITE acquired#Bob's transactions is committed [Bob]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection

Bob的共享鎖請(qǐng)求等待Alice的事務(wù)結(jié)束,以便釋放所有獲得的鎖。

情況6:PESSIMISTIC_WRITE阻止PESSIMISTIC_WRITE鎖定請(qǐng)求

排他鎖也阻止排他鎖:

@Test public void testPessimisticWriteBlocksPessimisticWrite() throws InterruptedException {LOGGER.info("Test PESSIMISTIC_WRITE blocks PESSIMISTIC_WRITE");testPessimisticLocking((session, product) -> {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_WRITE)).lock(product);LOGGER.info("PESSIMISTIC_WRITE acquired");},(session, product) -> {session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_WRITE)).lock(product);LOGGER.info("PESSIMISTIC_WRITE acquired");}); }

測試生成以下輸出:

[Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Test PESSIMISTIC_WRITE blocks PESSIMISTIC_WRITE#Alice selects the Product entity [Alice]: Time:1 Query:{[ SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_ FROM product lockmodepe0_ WHERE lockmodepe0_.id = ? ][1]} #Alice acquires an EXCLUSIVE lock on the Product entity [Alice]: Time:0 Query:{[ SELECT id FROM product WHERE id = ?AND version = ? FOR UPDATE ][1,0]} [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_WRITE acquired#Alice waits for 500ms [Alice]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - Wait 500 ms!#Bob selects the Product entity [Bob]: Time:1 Query:{[ SELECT lockmodepe0_.id AS id1_0_0_,lockmodepe0_.description AS descript2_0_0_,lockmodepe0_.price AS price3_0_0_,lockmodepe0_.version AS version4_0_0_ FROM product lockmodepe0_ WHERE lockmodepe0_.id = ? ][1]}#Alice's transactions is committed [Alice]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection#Bob can acquire the Product entity SHARED lock, only after Alice's transaction is committed [Bob]: Time:428 Query:{[ SELECT id FROM product WHERE id =? AND version =? FOR update ][1,0]} [Bob]: c.v.h.m.l.c.LockModePessimisticReadWriteIntegrationTest - PESSIMISTIC_WRITE acquired#Bob's transactions is committed [Bob]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection

Bob的排他鎖請(qǐng)求必須等待Alice釋放其鎖。

結(jié)論

關(guān)系數(shù)據(jù)庫系統(tǒng)使用鎖來保留ACID保證 ,因此了解共享和獨(dú)占行級(jí)鎖如何互操作非常重要。 顯式悲觀鎖是一種非常強(qiáng)大的數(shù)據(jù)庫并發(fā)控制機(jī)制,您甚至可以使用它來修復(fù)樂觀鎖競爭條件 。

  • 代碼可在GitHub上獲得 。

翻譯自: https://www.javacodegeeks.com/2015/02/hibernate-locking-patterns-how-does-pessimistic_read-and-pessimistic_write-work.html

總結(jié)

以上是生活随笔為你收集整理的休眠锁定模式– PESSIMISTIC_READ和PESSIMISTIC_WRITE如何工作的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。