加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net – 与蜘蛛交易相关的各种NHibernate错误

发布时间:2020-12-16 03:15:27 所属栏目:asp.Net 来源:网络整理
导读:我们有一个ASP.Net 4 / MVC 3混合Web应用程序,它使用NInject 3和(Fluent)NHibernate 3.2. DB是SQL Server 2008 R2.服务器是6核28 GB Windows 2008 64位服务器. 我们的客户最近开始使用蜘蛛工具测试该网站.一旦站点遇到蜘蛛产生的负载,我们的日志开始填满异常
我们有一个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();
    }
}

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

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

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;
    }

更多代码为你们和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();

这里是来自这些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; }

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

解决方法

错误消息表明您没有正确管理事务.我认为根本原因是你正在处理存储库方法中的事务,在我看来这是一个非常糟糕的设计.您的存储库应该将一个ISession注入其构造函数中,并且您的控制器应该具有它们依赖于注入其构造函数的任何存储库.使用Ninject可以轻松完成这一切.使用此方法,您可以使用每个请求事务或(更好地imo)管理操作方法中的事务.

以下是我在NinjectWebCommon中使用Ninject设置NHibernate的方法.您的问题的根本原因可能是您在请求范围中绑定了ISession并将其存储在HttpContext中,这是不必要的.我也很困惑为什么你有两组Domain和Query绑定.

private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<ISessionFactory>().ToProvider(new SessionFactoryProvider()).InSingletonScope();
        kernel.Bind<ISession>().ToProvider(new SessionProvider()).InRequestScope();
    }

    private class SessionFactoryProvider : Provider<ISessionFactory>
    {
        protected override ISessionFactory CreateInstance(IContext context)
        {
           // create and configure the session factory
           // I have a utility class to do this so the code isn't shown
           return nhibernateHelper.BuildSessionFactory();
        }
    }

    private class SessionProvider : Provider<ISession>
    {
        protected override ISession CreateInstance(IContext context)
        {
            var sessionFactory = context.Kernel.Get<ISessionFactory>();
            var session = sessionFactory.OpenSession();
            session.FlushMode = FlushMode.Commit;
            return session;
        }
    }

使用事务的示例控制器操作.管理存储库之外的事务非常重要,原因如下:

>允许多个存储库参与事务
>允许控制器设置事务边界(工作单元)
>允许在事务中发生延迟加载
>如果使用二级缓存,则需要事务进行读取操作.即使没有使用缓存,我认为这是一种最佳实践

public ActionResult EditDocuments(int id,string name)
{
    using (var txn = _session.BeginTransaction())
    {
        var summary = _characterizationRepository
            .GetCharacterization(id)
            .AsCharacterizationSummaryView()
            .ToFutureValue();

        var documents = _characterizationRepository
            .GetCharacterization(id)
            .SelectMany(c => c.Documents)
            .OrderBy(d => d.FileName)
            .AsDocumentSelectView(true)
            .ToFuture();

        if (summary.Value == null)
        {
            throw new NotFoundException(_characterizationRepository.ManualId,"Characterization",id);
        }

        CheckSlug(name,summary.Value.Title);

        var model = new DocumentSectionEditView()
            {
                CharacterizationSummary = summary.Value,Documents = documents.ToArray()
            };

        txn.Commit();
        return View(model);
    }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读