2016-08-19 53 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

相关问题