通过NHibernate查询SQL Server时超时已到期

时间:2012-02-08 12:48:39

标签: sql-server nhibernate locking

我有一个ASP.Net MVC应用程序,它通过NHibernate使用SQL Server 2005。我偶尔会收到以下错误消息:

  

“System.Data.SqlClient.SqlException(0x80131904):超时已过期。   在完成操作或之前经过的超时时间   服务器没有响应。在   System.Data.SqlClient.SqlConnection.OnError(SqlException异常,   Boolean breakConnection)at   System.Data.SqlClient.SqlInternalConnection.OnError(SQLEXCEPTION   exception,Boolean breakConnection)at   System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()at   System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior,   SqlCommand cmdHandler,SqlDataReader dataStream,   BulkCopySimpleResultSet bulkCopyHandler,TdsParserStateObject   stateObj)at   System.Data.SqlClient.SqlDataReader.SetMetaData(_SqlMetaDataSet   metaData,Boolean moreInfo)at   System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior,   SqlCommand cmdHandler,SqlDataReader dataStream,   BulkCopySimpleResultSet bulkCopyHandler,TdsParserStateObject   System.Data.SqlClient.SqlDataReader.ConsumeMetaData()中的stateObj)   在System.Data.SqlClient.SqlDataReader.get_MetaData()at   System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds,   RunBehavior runBehavior,String resetOptionsString)at   System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(的CommandBehavior   cmdBehavior,RunBehavior runBehavior,Boolean returnStream,Boolean   async)at   System.Data.SqlClient.SqlCommand.RunExecuteReader(的CommandBehavior   cmdBehavior,RunBehavior runBehavior,Boolean returnStream,String   方法,DbAsyncResult结果)at   System.Data.SqlClient.SqlCommand.RunExecuteReader(的CommandBehavior   cmdBehavior,RunBehavior runBehavior,Boolean returnStream,String   方法)at   System.Data.SqlClient.SqlCommand.ExecuteReader(的CommandBehavior   行为,String方法)at   System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(的CommandBehavior   行为)   System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader()
  在NHibernate.AdoNet.AbstractBatcher.ExecuteReader(IDbCommand cmd)
  在NHibernate.Loader.Loader.GetResultSet(IDbCommand st,Boolean   autoDiscoverTypes,布尔可调用,RowSelection选择,   ISessionImplementor会议)   NHibernate.Loader.Loader.DoQuery(ISessionImplementor session,   QueryParameters queryParameters,Boolean returnProxies)at   NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor   session,QueryParameters queryParameters,Boolean returnProxies)
  在NHibernate.Loader.Loader.DoList(ISessionImplementor session,   QueryParameters queryParameters)“

大多数情况下,系统运行正常并且反应灵敏。我查看了系统上的锁定,我通常发现有一个查询被另一个查询阻止:

"SELECT TOP 10 d.Id, d.Name FROM Documents d INNER JOIN Users u ON..."

被阻止:

"SELECT TOP 10 Id, Name FROM Users"

查看阻塞语句所持有的锁,在与Users表无关的各种表上有大约十几个独占(X)和(IX)页面和键锁(但这些是被阻止的查询的一部分) )。

这里没有涉及UPDATES,INSERTS或DELETES - 所以为什么一个只读查询会阻塞另一个,为什么在Users表上的简单查询会导致很多其他表的锁定。

2 个答案:

答案 0 :(得分:3)

SQL Server问题是数据库上的非默认“隔离级别”设置。 SQL Server具有ReadCommitted的默认隔离级别(锁定策略),这意味着尽快释放读取锁定,但在提交事务之前不会释放写入锁定。在Andy的回答中,默认的隔离级别将导致select被阻止。但是,如果数据库设置为RepeatableRead或Serializable,则选择将始终在事务持续时间内相互阻塞。可以使用此hibernate.cfg.xml配置在NHibernate中控制此设置:

<session-factory>
    ...
    <add key="hibernate.connection.isolation" value="ReadCommitted" />
    ...
</session-factory>

答案 1 :(得分:2)

这会导致问题:

begin transaction 

update Documents
set SomeField = 'SomeValue'
where SomeCondition = 'XXXX'

select top 10 Id, Name from Users

commit

在更新期间在文档表上创建的锁将不会被释放,直到您提交事务为止。这意味着连接可以将select语句作为其最新语句,但仍然保持上次更新的锁定。

一些想法:

  1. 确保您提交/回滚交易
  2. 尝试减少事务的长度(例如,在上面,运行select之前提交是否安全?)。
  3. 通过确保外键被编入索引来优化更新的连接也可能加快交易速度。
  4. 请注意,select本身只会生成共享锁。

    最后要注意(nolock)锁定提示的想法。阅读未提交的数据很少是一个好主意。