0

我有一个以 nHibernate 作为 ORM 的 ASP.NET MVC 应用程序(使用 SQL Server 作为数据库)。

每 5-6 个请求,就会抛出一个异常,其中包含上面标题中描述的随机错误。

这仅发生在GET请求上,并开始于:

错误在准备 SELECT ..

自从我将 NHibernate 4.x 升级到 NHibernate 5.0.3(现在是 5.1.1)后,这些问题就开始了。在此过程中,我还更新了目标框架,以前是 .NET 4.5.2 现在是 .NET 4.7.2。

我已经检查了所有内容,确保数据库没有任何连接泄漏或超时,但错误仍然存​​在。尝试从连接字符串中关闭“TransparentNetworkIPResolution”和“Enlist”功能 - 问题仍然存在。

任何关于解决问题的想法都将受到欢迎。

这是以下异常 (DepartmentService:838) 的罪魁祸首:

var department = _departmentRepository.Get(departmentId);

场景如下,我有多个网格,因此多个请求被触发到同一个动作。同一页面的每 5-6 次刷新,许多请求中的一个会失败(失败的一个请求是随机的,即有时是第 1 个,有时是第 2 个,依此类推)。

这是我的日志中的完整异常片段:

2020-06-26 13:25:16,297 [50] 错误 NHibernate.Util.ADOExceptionReporter [(null)] - 在准备 SELECT department0_.DepartmentId as departmentid1_22_0_,department0_.CreatedAt as createdat4_22_0_,department0_.ModifiedAt as modifiedat5_22_0_,department0_.Name as name2_22_0_, department0_.Status as status6_22_0_, department0_.CreatedBy as createdby7_22_0_, department0_.ModifiedBy as modifiedby8_22_0_, department0_.SiteId as siteid3_22_0_ FROM dbo.Departments department0_ WHERE department0_.DepartmentId=@p0 发生错误 2020-06-26 13:25: [50] 错误 NHibernate.Util.ADOExceptionReporter [(null)] - 请求的操作无法完成,因为连接已断开。

2020-06-26 13:25:16,300 [50] 错误 [(null)] - NHibernate.ADOException:在准备 SELECT department0_.DepartmentId as departmentid1_22_0_,department0_.CreatedAt as createdat4_22_0_,department0_.ModifiedAt as modifiedat5_22_0_,department0_.Name as name2_22_0_ ,department0_.Status as status6_22_0_,department0_.CreatedBy as createdby7_22_0_,department0_.ModifiedBy as modifiedby8_22_0_,department0_.SiteId as siteid3_22_0_ FROM dbo.Departments department0_ WHERE department0_.DepartmentId=@p0 发生错误---> System.InvalidOperationException:请求的操作无法完成,因为连接已断开。

在 System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransaction(TransactionRequest transactionRequest, 字符串名称, IsolationLevel iso, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest)
在 System.Data.SqlClient.SqlDelegatedTransaction.Initialize()
在 System.Transactions.TransactionStatePSPEOperation.PSPEInitialize(InternalTransaction tx, IPromotableSinglePhaseNotification promotableSinglePhaseNotification,Guid 启动器类型)
在 System.Transactions.TransactionStateActive.EnlistPromotableSinglePhase(InternalTransaction tx,IPromotableSinglePhaseNotification promotableSinglePhaseNotification,事务 atomicTransaction,Guid 启动器类型)
在 System.Transactions.Transaction.EnlistPromotableSinglePhase(IPromotableSinglePhaseNotification promotableSinglePhaseNotification,
GuidpromotableType)
在 System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
在 System.Data.SqlClient.
在 System.Data.ProviderBase.DbConnectionPool.PrepareConnection 的 System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction transaction)中登记(Transaction tx)
(DbConnection owningObject,DbConnectionInternal obj,Transaction 交易)
在 System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
在 System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource 1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection) at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource1 重试, DbConnectionOptions userOptions,
System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource 1 retry, DbConnectionOptions userOptions) at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource1 retry)
在 System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)在 System.Data.SqlClient 的DbConnectionInternal oldConnection, DbConnectionInternal& 连接)
。 SqlConnection.Open()
在 NHibernate.Connection.DriverConnectionProvider.GetConnection()
在 NHibernate.AdoNet.ConnectionManager.GetConnection()
在 NHibernate.AdoNet.AbstractBatcher.Prepare(DbCommand cmd)
--- 内部异常堆栈跟踪结束---

在 NHibernate.AdoNet.AbstractBatcher.Prepare(DbCommand cmd)
在 NHibernate.AdoNet.AbstractBatcher.ExecuteReader(DbCommand cmd)
在 NHibernate.Loader.Loader.GetResultSet(DbCommand st, QueryParameters queryParameters, ISessionImplementor session, IResultTransformer forceResultTransformer)
在 NHibernate.Loader。 Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies, IResultTransformerforcedResultTransformer)
在NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies, IResultTransformerforcedResultTransformer) 在 NHibernate.Loader.Loader.LoadEntity(ISessionImplementor session, Object id, IType identifierType, Object optionalObject, String optionalEntityName, Object optionalIdentifier, IEntityPersister 持久化器) 在 NHibernate.Loader.Entity.AbstractEntityLoader.Load(Object id, Object optionalObject, ISessionImplementor session) 在 NHibernate.Persister.Entity 的 NHibernate.Loader.Entity.AbstractEntityLoader.Load(ISessionImplementor session, Object id, Object optionalObject, Object optionalId) NHibernate.Event.Default.DefaultLoadEventListener 中的 .AbstractEntityPersister.Load(Object id, Object optionalObject, LockMode lockMode, ISessionImplementor session)。NHibernate.Event.Default.DefaultLoadEventListener.DoLoad(LoadEvent 事件,IEntityPersister 持久性,EntityKey keyToLoad,LoadType 选项)在 NHibernate.Event.Default.DefaultLoadEventListener.Load(LoadEvent 事件)的 LoadFromDatasource(LoadEvent 事件,IEntityPersister 持久性,EntityKey keyToLoad,LoadType 选项) , IEntityPersister 持久性, EntityKey keyToLoad, LoadType 选项) 在 NHibernate.Event.Default.DefaultLoadEventListener.ProxyOrLoad(LoadEvent 事件, IEntityPersister 持久性, EntityKey keyToLoad, LoadType 选项) 在 NHibernate.Event.Default.DefaultLoadEventListener.OnLoad(LoadEvent 事件, LoadType loadType)在 NHibernate.Impl.SessionImpl.FireLoad(LoadEvent event, LoadType loadType) 在 NHibernate.Impl.SessionImpl.Get(String entityName, Object id) 在 NHibernate.Impl.SessionImpl.Get[T](Object id) 在 Codera.Data。休眠。NH存储库1.Get(Object id) at Castle.Proxies.Invocations.NHRepository1_Get_10.InvokeMethodOnTarget() at Castle.DynamicProxy.AbstractInvocation.Proceed() at ISOQuest.Data.NHibernate.Interceptors.MethodInterceptor.Intercept(IInvocation invocation) 在 C:\Projects\ISOQuestGen6\ISOQuest.Data.NHibernate\Interceptors\MethodInterceptor.cs : 第 49 行 Castle.DynamicProxy.AbstractInvocation.Proceed() at Castle.Proxies.DepartmentRepositoryProxy.Get(Object id) at ISOQuest.Business.Services.DepartmentService.GetDepartmentAdministrators(Guid departmentId, Int32 type) in C:\Projects\ISOQuestGen6\ Modules\ISOQuest\ISOQuest.Business\Services\Department\DepartmentService.cs:第 838 行,位于 C:\Projects\ISOQuestGen6\Modules\ISOQuest\ISOQuest 中 ISOQuest.Web.Controllers.Api.DepartmentsController.LoadDepartmentAdministrators(Guid 部门 ID,Int32 类型) .Web\Controllers\Api\DepartmentsController.cs:lambda_method 处的第 454 行(闭包,ControllerBase , Object[] ) 在 System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary2 个参数)在 System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult 的 System.Web.Mvc.Async.AsyncControllerActionInvoker.b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState) 2.CallEndDelegate(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d() at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f() at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f() at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass21.<>c__DisplayClass2b.<BeginInvokeAction>b__1c() at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass21.<BeginInvokeAction>b__1e(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) at System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) 在 System.Web.Mvc.Controller。 System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) 在 System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid 1.CallEndDelegate(IAsyncResult asyncResult) at System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) at System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) 在 System.Web.HttpApplication.CallHandlerExecutionStep.System.Web的 EndExecuteCore(IAsyncResult asyncResult) .HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

4

1 回答 1

0

在尝试了一切之后,我又回到了 nHibernate 5.X 更改日志,在这里结束了:https ://nhibernate.info/doc/nhibernate-reference/transactions.html ,并在更改日志的最后找到了这个小注释:

从 NHibernate v5.0 开始,FlushMode.Commit 要求配置设置 transaction.use_connection_on_system_prepare 为 true,以便从事务范围提交刷新。否则,您有责任在完成范围之前刷新会话。

使用 transaction.use_connection_on_system_prepare 可能会导致不希望的事务提升分发:它需要使用专用连接进行刷新,并且会将会话处置(如果在范围内完成)延迟到范围处置。如果您想避免这种情况,请将此设置设置为 false 并手动刷新您的会话。

对于新应用程序,建议将 transaction.use_connection_on_system_prepare 设置为 false,并在范围完成之前显式刷新会话。对于旧应用程序,请考虑检查会话是如何刷新的,如果可能,也将其切换为 false。

基本上,我们在迁移到 nHibernate 5 时更改的一个设置是FlushMode从“Auto”到“Commit”,但不知何故错过了这个标志(transaction.use_connection_on_system_prepare = false)。

希望这将有助于其他尝试升级旧系统的人!

于 2020-07-02T09:23:39.930 回答