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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2023/12/3 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Hibernate锁定模式– PESSIMISTIC_READ和PESSIMISTIC_WRITE如何工作 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

介紹

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

  • 樂觀鎖定:實體狀態更改可以觸發版本增加
  • 行級鎖定:基于當前運行的事務隔離級別 ,INSERT / UPDATE / DELETE語句可能會獲取排他行鎖定

雖然隱式鎖定適用于許多情況,但顯式鎖定機制可以利用更細粒度的并發控制。

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

  • 樂觀的
  • OPTIMISTIC_FORCE_INCREMENT
  • PESSIMISTIC_FORCE_INCREMENT

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

  • PESSIMISTIC_READ
  • PESSIMISTIC_WRITE

讀寫器鎖

數據庫系統是高度并發的環境,因此許多并發理論習慣用法也適用于數據庫訪問。 必須將并發更改序列化以保留數據完整性,因此,即使通常通過Multiversion并發控制機制對其進行補充,大多數數據庫系統也使用兩階段鎖定策略。

因為互斥鎖定會阻礙可伸縮性(平等地進行讀寫操作),所以大多數數據庫系統都使用讀寫器鎖定同步方案,因此:

  • 共享(讀取)鎖會阻止作者,從而允許多個讀者繼續
  • 排他(寫入)鎖同時阻止讀取器和寫入器,從而使所有寫入操作順序地應用

因為鎖定語法不是SQL標準的一部分,所以每個RDBMS都選擇了不同的語法:

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

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

PostgreSQL行級鎖定模式

在下一個測試案例中,我們將使用PostgreSQL,因為它既支持獨占鎖定 ,也支持共享顯式鎖定 。

以下所有測試將使用相同的并發實用程序,模擬兩個用戶:Alice和Bob。 每個測試方案將驗證特定的讀/寫鎖定組合。

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鎖定請求

第一個測試將檢查兩個并發的PESSIMISTIC_READ鎖定請求如何交互:

@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");}); }

運行此測試,我們得到以下輸出:

[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

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

情況2:PESSIMISTIC_READ阻止UPDATE隱式鎖定請求

第二種情況將演示共享鎖如何防止并發修改。 愛麗絲將獲取共享鎖,而鮑勃將嘗試修改鎖定的實體:

@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實體,但UPDATE會一直延遲到提交Alice事務為止(這就是UPDATE花費427ms運行的原因)。

情況3:PESSIMISTIC_READ阻止PESSIMISTIC_WRITE鎖定請求

輔助PESSIMISTIC_WRITE鎖定請求也表現出相同的行為:

@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的排他鎖請求等待Alice的共享鎖被釋放。

情況4:PESSIMISTIC_READ阻止PESSIMISTIC_WRITE鎖定請求,NO WAIT快速失敗

Hibernate提供了一個PESSIMISTIC_NO_WAIT超時指令,該指令轉換為特定于數據庫的NO_WAIT鎖獲取策略。

PostgreSQL NO WAIT指令描述如下:

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

@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已經在與產品實體相關聯的數據庫行上持有共享鎖,因此Bob的排他鎖請求立即失敗。

情況5:PESSIMISTIC_WRITE阻止PESSIMISTIC_READ鎖定請求

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

@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的共享鎖請求等待Alice的事務結束,以便釋放所有獲得的鎖。

情況6:PESSIMISTIC_WRITE阻止PESSIMISTIC_WRITE鎖定請求

排他鎖也將阻止排他鎖:

@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的排他鎖請求必須等待Alice釋放其鎖。

結論

關系數據庫系統使用鎖來保留ACID保證 ,因此了解共享和排行級鎖如何互操作非常重要。 顯式悲觀鎖是一種非常強大的數據庫并發控制機制,您甚至可以使用它來修復樂觀鎖競爭條件 。

  • 代碼可在GitHub上獲得 。

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

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。