与蜘蛛交易过程中的交易有关的各种NHibernate错误

Mr *_*Moo 5 asp.net nhibernate asp.net-mvc ninject sql-server-2008

我们有一个ASP.Net 4/MVC 3混合Web应用程序,它使用NInject 3和(Fluent)NHibernate 3.2.DB是SQL Server 2008 R2.服务器是6核28 GB Windows 2008 64位服务器.

我们的客户最近开始使用蜘蛛工具测试该网站.一旦站点遇到蜘蛛产生的负载,我们的日志开始填满异常.

我们看到来自NHibernate的各种错误,包括以下一些错误:

  • NHibernate.TransactionException:使用SQL异常提交失败---> System.Data.SqlClient.SqlException:无法执行事务操作,因为有待处理的事务处理的请求.

  • System.Data.SqlClient.SqlException(0x80131904):服务器无法恢复事务.说明:410000050f.此会话中活动的事务已由另一个会话提交或中止.

  • System.NullReferenceException:未将对象引用设置为对象的实例.在System.Data.SqlClient.SqlInternalTransaction.GetServerTransactionLevel()....

  • NHibernate.Exceptions.GenericADOException:无法执行本机批量操作查询:exec [Stats.InsertListingStatsList] @ListingStats =:ListingStats [SQL:exec [Stats.InsertListingStatsList] @ListingStats = @ p0] ---> System.Data.SqlClient. SqlException:不允许启动新请求,因为它应该带有有效的事务描述符.

仅举四个例子.所有这些都有类似的风格 - 它们似乎都与ADO.Net作为NHibernate基础的交易管理有关.

现在,我们NH实施的一些细节:

  • SessionFactory是静态的;
  • SessionFactory使用AdoNetTransactionFactory;
  • ISession在请求范围内,并存储在HttpContext.Items集合中;
  • 存储库也在请求范围内;
  • 我们现在使用config.CurrentSessionContext();
  • 每次调用我们的通用存储库都使用一个事务

以下是我们的存储库中的两种方法.

public T GetById<T>(int id)
{
    using (var t = Session.BeginTransaction())
    {
        var entity = Session.Get<T>(id);
        t.Commit();
        return entity;
    }
}

public void Add<T>(T entity)
{
    using (var t = Session.BeginTransaction())
    {
        Session.Save(entity);
        t.Commit();
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题很简单:出了什么问题?是什么导致了交易之间或者我们的域名在我们的域名中解除的各种数据相关操作之间的这些明显冲突?

更新:这是我们的完整配置:

public FluentConfiguration BuildConfiguration(string connectionString)
{
    var sqlConfig = MsSqlConfiguration.MsSql2008.ConnectionString(connectionString).AdoNetBatchSize(30);

     var config = Fluently.Configure().Database(sqlConfig);

     var entityMapping = AutoMap.AssemblyOf<User>(new AutomappingConfiguration())
            .UseOverridesFromAssemblyOf<UserMappingOverride>()
            .AddMappingsFromAssemblyOf<TableNamingConvention>()
            .Conventions.AddFromAssemblyOf<TableNamingConvention>();

        var cqrsMapping = AutoMap.AssemblyOf<AdvertView>(new QueryAutomappingConfiguration())
            .UseOverridesFromAssemblyOf<AdvertViewMappingOverride>();

        config.Mappings(c => c.AutoMappings.Add(entityMapping));
        config.Mappings(c => c.AutoMappings.Add(cqrsMapping));

        config.Mappings(c => c.HbmMappings.AddFromAssemblyOf<AdvertView>());

        config.ExposeConfiguration(c => c.SetProperty(Environment.TransactionStrategy, typeof(AdoNetTransactionFactory).FullName));

        config.CurrentSessionContext<WebSessionContext>();

        return config;
    }
Run Code Online (Sandbox Code Playgroud)

更多代码为你们和gals.以下是IoC Container配置的相关部分.

var domainEntityBootstrapper = new DomainEntitySessionBootStrapper("Domain", "NHibernate.ISession.Domain", _enableLucine, HttpContextItemsProvider);
Bind<ISessionFactory>().ToMethod(domainEntityBootstrapper.CreateSessionFactory).InSingletonScope().Named(domainEntityBootstrapper.Name);
Bind<ISession>().ToMethod(domainEntityBootstrapper.GetSession).InRequestScope();

var queryBootstrapper = new QueryEntitySessionBootStrapper("Query", "NHibernate.ISession.Query", HttpContextItemsProvider);
Bind<ISessionFactory>().ToMethod(queryBootstrapper.CreateSessionFactory).InSingletonScope().Named(queryBootstrapper.Name);
Bind<ISession>().ToMethod(queryBootstrapper.GetSession).WhenInjectedInto(typeof (QueryExecutor)).InRequestScope();
Run Code Online (Sandbox Code Playgroud)

这里是来自这些SessionBootstrappers的基类的GetSession()方法的代码(请注意,CreateSessionFactory方法调用上面的BuildConfiguration方法,然后调用BuildSessionFactory()).

public virtual ISession GetSession(IContext context)
{
    var items = GetHttpContextItems();
    var session = default(ISession);
    var sessionExists = items.Contains(SessionKey);

    if (!sessionExists)
    {
        session = context.Kernel.Get<ISessionFactory>(Name).OpenSession();
        items.Add(SessionKey, session);
    }
    else
    {
        session = (ISession)items[SessionKey];
    }

    return session;
}

// a Func which serves access to the HttpContext.Current.Items collection
private Func<IDictionary> GetHttpContextItems { get; set; }
Run Code Online (Sandbox Code Playgroud)

请注意,我们使用两个会话,一个用于普通域de/hydration,一个用于CQRS,因此Container中的绑定对.

Pet*_*ter 0

您似乎使用了错误的上下文管理器,请检查您是否使用了 WebSessionContext。该上下文管理器会将您的会话绑定到当前调用的 httpcontext 而不是线程。现在在负载(蜘蛛)下发生了什么,当您使用 ThreadStaticSessionContext 时,会话将“跳转”到另一个“调用”。