1,數據庫事務並發會引起那些常見問題以及對應的解決方法?
1)丟失更新:撤消一個事務時,把其它事務已提交的更新的數據覆蓋了。
2)臟讀:一個事務讀到另一個事務未提交的更新數據。
3)幻讀:一個事務執行兩次查詢,但第二次查詢比第一次查詢多出了一些數據行。
4)不可重復讀:一個事務兩次讀同一行數據,可是這兩次讀到的數據不一樣。
---------------------------------------------------------------------------
9.6. 事務隔離級別
為了解決多個事務並發會引發的問題。數據庫系統提供了四種事務隔離級別供用戶選擇。
? Serializable:串行化。隔離級別最高。
? Repeatable Read:可重復讀。
? Read Committed:讀已提交數據。
? Read Uncommitted:讀未提交數據。隔離級別最差。
數據庫系統采用不同的鎖類型來實現以上四種隔離級別,具體的實現過程對用戶是透明的。用戶應該關心的是如何選擇合適的隔離級別。
對於多數應用程序,可以優先考慮把數據庫系統的隔離級別設為Read Committed,它能夠避免臟讀,而且具有較好的並發性能。
每個數據庫連接都有一個全局變量@@tx_isolation,表示當前的事務隔離級別。JDBC數據庫連接使用數據庫系統默認的隔離級別。在Hibernate的配置文件中可以顯示地設置隔離級別。每一種隔離級別對應着一個正整數。
? Read Uncommitted: 1
? Read Committed: 2
? Repeatable Read: 4
? Serializable: 8
在hibernate.cfg.xml中設置隔離級別如下:
<session-factory>
<!-- 設置JDBC的隔離級別 -->
<property name="hibernate.connection.isolation">2</property>
</session-factory>
設置之后,在開始一個事務之前,Hibernate將為從連接池中獲得的JDBC連接設置級別。需要注意的是,在受管理環境中,如果Hibernate使用的數據庫連接來自於應用服務器提供的數據源,Hibernate不會改變這些連接的事務隔離級別。在這種情況下,應該通過修改應用服務器的數據源配置來修改隔離級別。
9.7. 並發控制
當數據庫系統采用Red Committed隔離級別時,會導致不可重復讀和第二類丟失更新的並發問題,在可能出現這種問題的場合。可以在應用程序中采用悲觀鎖或樂觀鎖來避免這類問題。
9.8. 樂觀鎖(Optimistic Locking)
樂觀鎖假定當前事務操縱數據資源時,不會有其他事務同時訪問該數據資源,因此不作數據庫層次上的鎖定。為了維護正確的數據,樂觀鎖使用應用程序上的版本控制(由程序邏輯來實現的)來避免可能出現的並發問題。
唯一能夠同時保持高並發和高可伸縮性的方法就是使用帶版本化的樂觀並發控制。版本檢查使用版本號、 或者時間戳來檢測更新沖突(並且防止更新丟失)。
9.9. 使用版本檢查(<version>)
Hibernate中通過版本號檢查來實現后更新為主,這也是Hibernate推薦的方式。在數據庫表中加入一個version(版本)字段,在讀取數據時連同版本號一起讀取,並在更新數據時比較版本號與數據庫表中的版本號,如果等於數據庫表中的版本號則予以更新,並遞增版本號,如果小於數據庫表中的版本號就拋出異常。
9.10. 使用時間戳(<timestamp>)
跟版本檢查的用法相似。不再多說。
9.11. 悲觀鎖(Pessimistic Locking)
悲觀鎖假定當前事務操縱數據資源時,肯定還會有其他事務同時訪問該數據資源,為了避免當前事務的操作受到干擾,先鎖定資源。盡管悲觀鎖能夠防止丟失更新和不可重復讀這類並發問題,但是它影響並發性能,因此應該很謹慎地使用悲觀鎖。
為了解決多個事務並發會引發的問題。數據庫系統提供了四種事務隔離級別供用戶選擇。
? Serializable:串行化。隔離級別最高。
? Repeatable Read:可重復讀。
? Read Committed:讀已提交數據。
? Read Uncommitted:讀未提交數據。隔離級別最差。
數據庫系統采用不同的鎖類型來實現以上四種隔離級別,具體的實現過程對用戶是透明的。用戶應該關心的是如何選擇合適的隔離級別。
對於多數應用程序,可以優先考慮把數據庫系統的隔離級別設為Read Committed,它能夠避免臟讀,而且具有較好的並發性能。
每個數據庫連接都有一個全局變量@@tx_isolation,表示當前的事務隔離級別。JDBC數據庫連接使用數據庫系統默認的隔離級別。在Hibernate的配置文件中可以顯示地設置隔離級別。每一種隔離級別對應着一個正整數。
? Read Uncommitted: 1
? Read Committed: 2
? Repeatable Read: 4
? Serializable: 8
在hibernate.cfg.xml中設置隔離級別如下:
<session-factory>
<!-- 設置JDBC的隔離級別 -->
<property name="hibernate.connection.isolation">2</property>
</session-factory>
設置之后,在開始一個事務之前,Hibernate將為從連接池中獲得的JDBC連接設置級別。需要注意的是,在受管理環境中,如果Hibernate使用的數據庫連接來自於應用服務器提供的數據源,Hibernate不會改變這些連接的事務隔離級別。在這種情況下,應該通過修改應用服務器的數據源配置來修改隔離級別。
9.7. 並發控制
當數據庫系統采用Red Committed隔離級別時,會導致不可重復讀和第二類丟失更新的並發問題,在可能出現這種問題的場合。可以在應用程序中采用悲觀鎖或樂觀鎖來避免這類問題。
9.8. 樂觀鎖(Optimistic Locking)
樂觀鎖假定當前事務操縱數據資源時,不會有其他事務同時訪問該數據資源,因此不作數據庫層次上的鎖定。為了維護正確的數據,樂觀鎖使用應用程序上的版本控制(由程序邏輯來實現的)來避免可能出現的並發問題。
唯一能夠同時保持高並發和高可伸縮性的方法就是使用帶版本化的樂觀並發控制。版本檢查使用版本號、 或者時間戳來檢測更新沖突(並且防止更新丟失)。
9.9. 使用版本檢查(<version>)
Hibernate中通過版本號檢查來實現后更新為主,這也是Hibernate推薦的方式。在數據庫表中加入一個version(版本)字段,在讀取數據時連同版本號一起讀取,並在更新數據時比較版本號與數據庫表中的版本號,如果等於數據庫表中的版本號則予以更新,並遞增版本號,如果小於數據庫表中的版本號就拋出異常。
9.10. 使用時間戳(<timestamp>)
跟版本檢查的用法相似。不再多說。
9.11. 悲觀鎖(Pessimistic Locking)
悲觀鎖假定當前事務操縱數據資源時,肯定還會有其他事務同時訪問該數據資源,為了避免當前事務的操作受到干擾,先鎖定資源。盡管悲觀鎖能夠防止丟失更新和不可重復讀這類並發問題,但是它影響並發性能,因此應該很謹慎地使用悲觀鎖。