JPA Hibernate 和資料庫 的 鎖機制
本文總結Java中有關資料庫儲存持久資料的鎖機制,不只是純粹資料庫自身的鎖,本文主要就Java持久層三個技術資料庫、JPA和Hibernate的鎖應用進行了總結。
在併發理論中,鎖是用於保護可變的共享資料,以保證資料的完整性,大多數應用程式都是依賴於資料庫本身提供的隱藏在資料庫機制內的鎖技術,很多初學者可能都沒有意識到。
將整個系統的鎖職責委託給資料庫系統,雖然可以簡化應用程式的開發,防止併發問題如死鎖,但是還是有可能出現死鎖的,但是資料庫可以檢測到並採取安全措施,比如任意釋放兩個競爭鎖中一個。
物理鎖
大多數的資料庫系統使用的是共享讀鎖和排他寫鎖,這是因為其特定的鎖元素(行 表),而物理鎖是由SQL標準確定的,其悲觀的方式可能或妨礙系統的伸縮擴充套件性Scalable。
大多數資料庫是使用輕量的鎖技術,比如多版本併發控制,隱式的資料庫鎖機制的背後是事物隔離級別設定ACID,每個隔離級別是一個預定義的鎖方案,目的是防止某一組資料的完整性異常。
READ COMMITTED(已提交讀取)是使用查詢級別的共享鎖,對於當前事務中修改資料的操作採取排他鎖,REPEATABLE (可重複讀)和SERIALIZABLE (序列化)是在讀取和寫入排他鎖需要時使用事務級別的共享鎖。
邏輯鎖
如果說資料庫鎖對於批處理系統已經足夠,那麼對於跨越多個數據庫的多個Web請求來說,這種長對話事務需要一個邏輯(樂觀)鎖機制則是更合適些。
Hibernate提供的樂觀鎖(conversation-level repeatable read storage)可以確保資料的完整性,但是缺乏交易的可擴充套件性;JPA提供樂觀鎖和持久上下文可重複讀兩種機制,為實現邏輯鎖提供了多樣選擇。
顯式鎖
前面提到由資料庫和持久框架提供的隱式鎖已經滿足大多數應用程式的併發控制要求了,但是有時如果你需要一個更細粒度的鎖策略,那麼就需要使用顯式鎖了。
大多數資料庫系統支援查詢時間獨佔鎖指令,如 SELECT FOR UPDATE or SELECT FOR SHARE,因此我們可以使用較低級別的預設隔離級別(READ COMMITTED),而具體交易情況,使用共享和獨佔鎖。
大部分樂觀鎖實現只是驗證修改的資料,但是JPA允許你明確指定樂觀鎖的方式。
JPA鎖
作為資料庫抽象層,JPA能夠從底層RDBMS鎖獲得隱式的鎖機制,JPA也提供優化可選自動的屍體版本控制機制。JPA提供顯式鎖為了如下操作:
顯式鎖型別
鎖作用域和超時
JPA 2.0通過下面值定義javax.persistence.lock.scope:
- NORMAL因為物件圖會跨越多個數據表,一個顯式鎖也會涉及到多個表(例如 joined inheritance, secondary tables).因為整個實體相關聯的行被鎖住, many-to-one多對一 和 一對一one-to-one外來鍵將鎖定,但不會鎖定對方父關聯,這個作用域不會涉及到子集。
- EXTENDED這個顯式鎖將涉及到元素集合和junction tables, 但是不會實際鎖定子實體,這個鎖用於防止刪除現有的子物件是有用的,同時允許幻讀phantom reads 或實際子實體狀態的改變。
JPA 2.0也引入了javax.persistence.lock.timeout屬性,我們能夠配置多少毫秒超時,這樣一個請求在這個鎖必須等待一直到過了超時,然後會丟擲PessimisticLockException。
Hibernate鎖
Hibernate支援所有JPA鎖模型,有一些附加的特定鎖選項,顯式鎖能針對如下操作配置: