休眠锁定模式– OPTIMISTIC_FORCE_INCREMENT锁定模式如何工作
介紹
在我以前的文章中 ,我解釋了OPTIMISTIC鎖定模式是如何工作的,以及它如何幫助我們同步外部實體狀態(tài)更改。 在本文中,我們將介紹OPTIMISTIC_FORCE_INCREMENT鎖定模式的使用模式。
使用LockModeType.OPTIMISTIC ,將在當前正在運行的事務(wù)結(jié)束時檢查鎖定的實體版本,以確保我們不使用陳舊的實體狀態(tài)。 由于應(yīng)用程序級驗證的性質(zhì) ,該策略易受競爭條件的影響,因此需要附加的悲觀鎖 。
LockModeType.OPTIMISTIC_FORCE_INCREMENT不僅會檢查預期的鎖定實體版本,還會對其進行遞增。 檢查和更新都發(fā)生在同一UPDATE語句中,因此利用了當前數(shù)據(jù)庫事務(wù)隔離級別和關(guān)聯(lián)的物理鎖定保證。
值得注意的是,即使當前運行的事務(wù)未更改實體狀態(tài),鎖定的實體版本也會被提高。
集中版本控制用例
作為練習,我們將模擬一個集中化的版本控制系統(tǒng) ,其建模如下:
存儲庫是我們的系統(tǒng)根實體,每個狀態(tài)更改都由Commit子實體表示。 每個Commit可能包含一個或多個Change組件,這些組件作為單個原子工作單元傳播。
存儲庫版本隨著每個新的Commit而增加。 為簡單起見,我們只驗證存儲庫實體版本,盡管更現(xiàn)實的方法肯定會檢查每個單獨的文件版本(以允許無沖突的提交并發(fā)進行)。
測試時間
首先,我們應(yīng)該檢查OPTIMISTIC_FORCE_INCREMENT鎖定模式是否符合我們的用例要求:
doInTransaction(new TransactionCallable<Void>() {@Overridepublic Void execute(Session session) {Repository repository = (Repository) session.get(Repository.class, 1L);session.buildLockRequest(new LockOptions(LockMode.OPTIMISTIC_FORCE_INCREMENT)).lock(repository);Commit commit = new Commit(repository);commit.getChanges().add(new Change("README.txt", "0a1,5..."));commit.getChanges().add(new Change("web.xml", "17c17..."));session.persist(commit);return null;} });此代碼生成以下輸出:
#Alice selects the Repository and locks it using an OPTIMISTIC_FORCE_INCREMENT Lock Mode Query:{[select lockmodeop0_.id as id1_2_0_, lockmodeop0_.name as name2_2_0_, lockmodeop0_.version as version3_2_0_ from repository lockmodeop0_ where lockmodeop0_.id=?][1]} #Alice makes two changes and inserts a new Commit Query:{[select lockmodeop0_.id as id1_2_0_, lockmodeop0_.name as name2_2_0_, lockmodeop0_.version as version3_2_0_ from repository lockmodeop0_ where lockmodeop0_.id=?][1]} Query:{[insert into commit (id, repository_id) values (default, ?)][1]} Query:{[insert into commit_change (commit_id, diff, path) values (?, ?, ?)][1,0a1,5...,README.txt]} Query:{[insert into commit_change (commit_id, diff, path) values (?, ?, ?)][1,17c17...,web.xml]} #The Repository version is bumped up Query:{[update repository set version=? where id=? and version=?][1,1,0]}我們的用戶選擇了一個存儲庫并發(fā)布了一個新的Commit 。 在交易結(jié)束時, 存儲庫版本也會增加(因此記錄新的存儲庫狀態(tài)更改)。
沖突檢測
在下一個示例中,我們將有兩個用戶(愛麗絲和鮑勃)同時提交更改。 為避免丟失更新 ,兩個用戶都獲得了顯式的OPTIMISTIC_FORCE_INCREMENT鎖定模式。
在Alice獲得提交機會之前,Bob剛剛完成了交易并增加了Repository版本。 Alice事務(wù)將回滾,并引發(fā)不可恢復的 StaleObjectStateException 。
為了模擬沖突檢測機制,我們將使用以下測試方案:
doInTransaction(new TransactionCallable<Void>() {@Overridepublic Void execute(Session session) {Repository repository = (Repository) session.get(Repository.class, 1L);session.buildLockRequest(new LockOptions(LockMode.OPTIMISTIC_FORCE_INCREMENT)).lock(repository);executeAndWait(new Callable<Void>() {@Overridepublic Void call() throws Exception {return doInTransaction(new TransactionCallable<Void>() {@Overridepublic Void execute(Session _session) {Repository _repository = (Repository) _session.get(Repository.class, 1L);_session.buildLockRequest(new LockOptions(LockMode.OPTIMISTIC_FORCE_INCREMENT)).lock(_repository);Commit _commit = new Commit(_repository);_commit.getChanges().add(new Change("index.html", "0a1,2..."));_session.persist(_commit);return null;}});}});Commit commit = new Commit(repository);commit.getChanges().add(new Change("README.txt", "0a1,5..."));commit.getChanges().add(new Change("web.xml", "17c17..."));session.persist(commit);return null;} });生成以下輸出:
#Alice selects the Repository and locks it using an OPTIMISTIC_FORCE_INCREMENT Lock Mode Query:{[select lockmodeop0_.id as id1_2_0_, lockmodeop0_.name as name2_2_0_, lockmodeop0_.version as version3_2_0_ from repository lockmodeop0_ where lockmodeop0_.id=?][1]} #Bob selects the Repository and locks it using an OPTIMISTIC_FORCE_INCREMENT Lock Mode Query:{[select lockmodeop0_.id as id1_2_0_, lockmodeop0_.name as name2_2_0_, lockmodeop0_.version as version3_2_0_ from repository lockmodeop0_ where lockmodeop0_.id=?][1]} #Bob makes a change and inserts a new Commit Query:{[insert into commit (id, repository_id) values (default, ?)][1]} Query:{[insert into commit_change (commit_id, diff, path) values (?, ?, ?)][1,0a1,2...,index.html]} #The Repository version is bumped up to version 1 Query:{[update repository set version=? where id=? and version=?][1,1,0]} #Alice makes two changes and inserts a new Commit Query:{[insert into commit (id, repository_id) values (default, ?)][1]} Query:{[insert into commit_change (commit_id, diff, path) values (?, ?, ?)][2,0a1,5...,README.txt]} Query:{[insert into commit_change (commit_id, diff, path) values (?, ?, ?)][2,17c17...,web.xml]} #The Repository version is bumped up to version 1 and a conflict is raised Query:{[update repository set version=? where id=? and version=?][1,1,0]} INFO [main]: c.v.h.m.l.c.LockModeOptimisticForceIncrementTest - Failure: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.vladmihalcea.hibernate.masterclass.laboratory.concurrency. LockModeOptimisticForceIncrementTest$Repository#1]此示例表現(xiàn)出與典型的隱式樂觀鎖定機制相同的行為。 唯一的區(qū)別在于版本更改發(fā)起者。 雖然隱式鎖定僅適用于修改實體,但是顯式鎖定可以跨任何托管實體使用(忽略實體狀態(tài)更改要求)。
結(jié)論
因此, OPTIMISTIC_FORCE_INCREMENT對于將子實體狀態(tài)更改傳播到未修改的父實體非常有用。 通過簡單地鎖定它們的公共父代,此模式可以幫助我們同步各種實體類型。
當子實體狀態(tài)更改必須觸發(fā)父實體版本增加時,您可能追求的是顯式OPTIMISTIC_FORCE_INCREMENT鎖定模式。
- 代碼可在GitHub上獲得 。
翻譯自: https://www.javacodegeeks.com/2015/02/hibernate-locking-patterns-optimistic_force_increment-lock-mode-work.html
總結(jié)
以上是生活随笔為你收集整理的休眠锁定模式– OPTIMISTIC_FORCE_INCREMENT锁定模式如何工作的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 手机自动接听怎么设置(智能手机自动接听怎
- 下一篇: 世界史上最大的猫科动物(迄今为止猫科中最