我们使用Fluent NHibernate进行NHibernate 3.1设置,并使用StructureMap 2.6.1管理会话的生命期。这是使用VB.NET的Web应用程序(有些项目是用C#)。NHibernate泄漏连接/事务
我们从生产中获取异常,听起来像多个线程试图使用相同的连接/事务。这些仅在打开连接池时发生。打开连接池清除这些例外,但我们看到重大的性能问题,所以这是一个暂时的修复。
当调用session.BeginTransaction()
服务器无法恢复交易。说明:970000004d。 此会话中处于活动状态的事务已被另一个会话提交或中止。
当调用transaction.Rollback()
事务未连接,或线路被断开
当试图通过StructureMap注入的Isession。 (这仅在连接池关闭时偶尔发生。)
超时已过期。操作完成之前超时的时间或服务器没有响应。
我们NHibernateRegistry为SturctureMap看起来是这样的:
var dbConfiguration = MsSqlConfiguration.MsSql2008.ConnectionString(ModuleConfig.GetSettings().NHibernateConnectionString)
.AdoNetBatchSize(100).IsolationLevel(IsolationLevel.ReadCommitted);
var cfg = Fluently.Configure()
.Database(dbConfiguration)
.Mappings(m =>
{
m.FluentMappings.AddFromAssemblyOf<MapMarker>();
m.AutoMappings.Add(AutoMap.AssemblyOf<EntityMarker>()
.Where(x =>
x.GetInterface(typeof(ISubClassEntity).Name) == null &&
x.GetInterface(typeof(IFakeEntity).Name) == null &&
typeof(BaseEntity).IsAssignableFrom(x))
.Conventions.AddFromAssemblyOf<ConventionsMarker>()
.UseOverridesFromAssemblyOf<OverridesMarker>()
.OverrideAll(map => map.IgnoreProperties(x => !x.CanWrite && !x.Name.EndsWith("Id") && !x.PropertyType.IsEnumerable())));
})
.Cache(c => c.UseQueryCache().ProviderClass(typeof(DotNetCacheProvider).AssemblyQualifiedName));
cfg.ExposeConfiguration(x =>
{
// custom tuplizers here, removed from snippet.
x.SetProperty("adonet.batch_size", "50");
});
var sessionFactory = cfg.BuildSessionFactory();
For<ISessionFactory>().Singleton().Use(sessionFactory);
For<ISession>().HybridHttpOrThreadLocalScoped().Use(cx =>
{
var session = cx.GetInstance<ISessionFactory>().OpenSession();
session.FlushMode = FlushMode.Commit;
session.SetBatchSize(50);
return session;
});
在每个请求的结束,我们清理StructureMap与在Global.asax以下电话:
Sub Application_EndRequest(ByVal sender As Object, ByVal e As EventArgs)
' Make sure we dipose of all http scoped objects
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects()
End Sub
我们有一个方法,我们传递一个Func来处理我们的事务。这是代码的样子:
protected virtual TResult Transact<TResult>(Func<TResult> func)
{
if (!session.Transaction.IsActive)
{
TResult result;
using (var transaction = session.BeginTransaction())
{
try
{
result = func.Invoke();
transaction.Commit();
}
catch(Exception ex)
{
// Make sure the transaction is still active...
if(session.Transaction.IsActive)
{
transaction.Rollback();
}
throw new InvalidOperationException("There was an error while executing within an NHibernate Transaction.", ex);
}
}
return result;
}
return func.Invoke();
}
为了防止使用隐式事务,我们使用这种Transact方法来处理SELECT语句。此方法的调用看起来像这样(会话使用构造器注入通过StructureMap注入):
public T Get(TId id)
{
return Transact(() => session.Get<T>(id));
}
我的问题是,我们该如何停止从多个线程之间共享的连接,导致上述异常?如果您需要更多信息,请告诉我。
不应该将StructureMap中的ISession变量的范围设置为HybridHttpOrThreadLocalScoped确保每个线程/ http请求都有单独的会话? –
如果您处于WCF环境(通过WCF调用访问),则不存在http上下文,并且线程将在多次调用中重复使用。 – Peter