2016-08-19 55 views
0

我正在構建一個基於Java的Web應用程序,該應用程序可用於SQL Server。用於Web應用程序的SQL服務器數據庫隔離級別

SQL服務器的默認數據庫隔離級別是READ_COMMITTED。

我得到以下異常:

Cause: org.hibernate.exception.LockAcquisitionException: Transaction (Process ID 124) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction. 

    2016-08-18 07:23:36.064 ERROR application 

    Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Transaction (Process ID 124) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction. 
     at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:216) ~[com.microsoft.sqlserver.sqljdbc4-4.0.jar:na] 
     at com.microsoft.sqlserver.jdbc.SQLServerResultSet$FetchBuffer.nextRow(SQLServerResultSet.java:4853) ~[com.microsoft.sqlserver.sqljdbc4-4.0.jar:na] 
     at com.microsoft.sqlserver.jdbc.SQLServerResultSet.fetchBufferNext(SQLServerResultSet.java:1781) ~[com.microsoft.sqlserver.sqljdbc4-4.0.jar:na] 
     at com.microsoft.sqlserver.jdbc.SQLServerResultSet.next(SQLServerResultSet.java:1034) ~[com.microsoft.sqlserver.sqljdbc4-4.0.jar:na] 
     at sun.reflect.GeneratedMethodAccessor25.invoke(Unknown Source) ~[na:na] 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_74] 
     at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_74] 
     at org.hibernate.engine.jdbc.internal.proxy.AbstractResultSetProxyHandler.continueInvocation(AbstractResultSetProxyHandler.java:104) ~[org.hibernate.hibernate-core-4.1.9.Final.jar:4.1.9.Final] 
     ... 82 common frames omitted 

有人可以給更多的相關信息?

+0

https://technet.microsoft.com/en-us/library/ms178104 %28v = sql.105%29.aspx –

+0

同樣的應用程序在Mariadb沒有死鎖的情況下工作得很好,我對此有點困惑。 –

回答

0

默認情況下,sql server使用悲觀鎖定。這意味着當一個行被讀取或在一個事務中被更新時,它被該事務鎖定,所以沒有其他事務可以讀或寫(另一個事務會阻塞,直到第一個事務被提交)

當你有兩個事務讀取相同的數據,並鎖定另一個事務正在讀取的行。

以一個簡單的例子: 你有一個桌子,上面列名爲名和2行:

名稱:

酒吧

事務1讀取美孚(導致它鎖)
事務2讀取Bar(導致它鎖定)
事務1嘗試讀取Bar,但會阻塞,直到事務2提交
事務2嘗試讀取Foo,但是通過事務1阻止

您現在有一個死鎖,兩個事務正在等待另一個釋放該資源。 Sql服務器有一個內部機制來檢測死鎖,它會檢測到死鎖並選擇一個事務來回滾。事務被選爲死鎖受害者的java線程將返回一個類似於你的例子的錯誤。

解決辦法: 在這裏,你有幾種選擇

  1. 如果可能的話,改變你的代碼,以便被讀取的行以相同的順序總是讀(在上面如果兩個交易閱讀的例子foo第一個事務2將簡單地等待事務1完成)

  2. 接受該死鎖可以是併發應用程序的一部分,並允許用戶重新提交請求或創建一些代碼,如果此錯誤可以自動重新提交請求被拋出。 (不理想,但取決於問題的頻率,偶爾會發生這些錯誤有時是務實的)

  3. 看看替代的鎖定策略。 SQL服務器支持多種類型,但它們可以大致分爲2類,悲觀鎖(默認和您的示例中相同)和樂觀鎖(有時稱爲快照隔離)。
    樂觀鎖定允許多個事務在不鎖定的情況下讀取同一行,鎖定僅在寫入時才需要。這兩種方法都有優點和缺點,改變這種做法可能會導致問題的發生。
    在上面的例子中,樂觀鎖定可以解決這個問題,因爲這兩個事務只讀。但是,如果兩個事務正在插入或更新記錄,那麼您可以簡單地通過樂觀鎖定來解決問題,如果兩個事務嘗試更新相同的記錄(在兩個事務已經讀取但都未提交之後),最後提交的事務將獲得樂觀鎖定錯誤。
    還有很多其他方面需要考慮,並且有些優秀的文章可以更詳細地介紹。

https://technet.microsoft.com/en-us/library/jj856598(v=sql.110).aspx

https://msdn.microsoft.com/en-us/library/tcbchxcb(v=vs.110).aspx

相關問題