2010-04-03 84 views
2

我的朋友描述了一個場景,並挑戰我找到解決方案。他正在使用Oracle數據庫和JDBC連接,並將讀取提交爲事務隔離級別。在其中一個交易中,他更新記錄,執行選擇語句並提交交易。當一切發生在一個線程內時,事情都很好。但是,當處理多個請求時,發生死鎖。JDBC事務死鎖:需要解決方案嗎?

  1. 線程A更新記錄。
  2. 線程B更新另一條記錄。
  3. 線程A發出select語句並等待線程B的事務完成提交操作。
  4. 線程B發出select語句並等待線程A的事務完成提交操作。

以上原因導致死鎖。由於它們使用命令模式,因此基本框架只允許發出一次提交(在所有數據庫操作結束時),因此它們無法在選擇語句之前立即發出提交。

我的論點是:線程-A應該選擇所有提交的記錄,因此不應該發佈。但他表示,線程A肯定會等到線程B提交記錄。真的嗎?

什麼是所有的方式,以避免上述問題?是否有可能改變隔離級別(不改變底層java框架)?

有關基本框架的一些信息:它與Struts動作類似,每個請求都由一個動作處理,事務在執行前開始並在執行後提交。

+0

我不明白「等待......交易完成」,因爲在Oracle讀取提交時,讀者不會阻止作者和作者不會阻止讀者。 – davek 2010-04-03 16:14:06

回答

0

here

甲骨文明確支持,因爲他們在 標準正在定義的READ Committed和Serializable隔離 水平。但是,這並不能告訴整個故事。 SQL標準是 嘗試設置隔離級別,即 將允許在各個級別在 執行的查詢的不同程度的 一致性。 REPEATABLE READ是隔離級別,SQL標準 聲稱將保證 與查詢的讀取一致性結果。 在SQL標準定義中,READ COMMITTED不會給您一致的 結果,而READ UNCOMMITTED是 級別用於獲取非阻塞式讀取。

但是,在Oracle數據庫中,READ COMMITTED具有實現讀取一致性 查詢所需的所有屬性 。在其他數據庫中,READ COMMITTED查詢可以並將返回 數據庫中從未存在的答案。此外,Oracle數據庫 也支持未讀的精神。提供 髒讀的目標是提供非阻塞 讀取,從而查詢不會被 阻止,也不會阻止更新 相同的數據。但是,Oracle數據庫 不需要髒讀來實現此目標,也不支持它們。 髒讀是其他數據庫必須使用的實現 提供 非阻塞讀取。

閱讀 COMMITTED。 READ COMMITTED隔離級別指出 事務可能只讀取已在數據庫中提交的數據,其中 已被提交。 沒有髒讀(未讀數據的讀取爲 )。有可能是 不可重複讀(即重新讀取同一行可能會在同一事務返回不同的 答案 )和 幻像讀(即,新插入 和提交的行成爲一個 查詢間沒有」可見t在 之前可見的交易行爲)。 READ COMMITTED是 也許是數據庫中最常用的 隔離級別 應用程序,它是Oracle Database的默認模式 。很難看到 在Oracle數據庫中使用的不同的隔離級別 級別。

在 Oracle數據庫,使用 多版本和讀一致 查詢,我從 賬戶查詢得到的答覆是在READ COMMITTED 例如相同的,因爲它是在 讀取未提交的例子。 Oracle 數據庫將重建修改的 數據,因爲它在查詢 開始時出現,並在查詢 開始時返回數據庫中的 答案。

3

我相信你的朋友是正確的如果選擇是由其他線程的結果已經被更新(但還未提交)的更新。如果他們只是簡單地選擇數據,並且JDBC框架無法通過強制選擇更新來幫助您,那麼您是正確的。

要避免此問題,請確保您只在真正需要時選擇更新,在這種情況下,請使用select中的NOWAIT選項。如果操作阻塞,這將導致錯誤發生。

Oracle將檢測到死鎖並回滾相關事務之一。

0

Oracle提供的場景不會發生,原因很簡單,寫入操作不會阻塞該數據庫中的讀取操作。

在哪裏,我們可以得到一個僵局是在這樣的場景:

  1. 會話一個更新記錄,#1234。
  2. 會話B更新另一條記錄#5678。
  3. 會話A更新記錄#5678。
  4. 會話B更新記錄#1234。
  5. 會話A發出提交。
  6. 會話B發出提交。

Oracle將檢測到死鎖並回滾其中一個會話。在傳統的客戶端/服務器應用程序中,這種情況通過悲觀鎖定(SELECT ... FOR UPDATE)得以避免。在Web應用程序中,通過使用「樂觀鎖列」避免了這種情況,它實際上根本沒有任何鎖定形式(這就是爲什麼它避免了死鎖,儘管是以大量額外的讀取爲代價)。