【问题标题】:Timeout expired. - Using Db in ServiceStack Service超时已过。 - 在 ServiceStack 服务中使用 Db
【发布时间】:2013-11-12 11:20:46
【问题描述】:

我在 ServiceStack 服务中使用 Db 属性来访问我的数据库,但我时不时地从 IIS 收到以下错误:

Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.

堆栈跟踪:

[InvalidOperationException: Timeout expired.  The timeout period elapsed prior to obtaining a connection from the pool.  This may have occurred because all pooled connections were in use and max pool size was reached.]
   System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection) +6371713
   System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) +6372046
   System.Data.SqlClient.SqlConnection.Open() +300
   ServiceStack.OrmLite.OrmLiteConnection.Open() +44
   ServiceStack.OrmLite.OrmLiteConnectionFactory.OpenDbConnection() +132
   ServiceStack.ServiceInterface.Service.get_Db() +68

我已将Configure 方法中的ReuseScope 设置为ReuseScope.None,我相信这应该根据每个请求关闭连接?我在这里做错了什么?

public override void Configure(Container container)
{
    JsConfig.EmitCamelCaseNames = true;

    //Register all your dependencies
    ConfigureDb(container);

    //Set MVC to use the same Funq IOC as ServiceStack
    ControllerBuilder.Current.SetControllerFactory(new FunqControllerFactory(container));
}

配置数据库:

private static void ConfigureDb(Container container)
{
    var connectionString = ConfigurationManager.ConnectionStrings["AppDb"].ConnectionString;
    container.Register<IDbConnectionFactory>(c =>
        new OrmLiteConnectionFactory(connectionString, SqlServerDialect.Provider))
        .ReusedWithin(ReuseScope.None);

    using (var db = container.Resolve<IDbConnectionFactory>().Open())
    {
      // Do database seed/initialisation
    }
}

编辑

经过更多诊断,当我调用此服务方法时,似乎发生了几次刷新页面:

public Warranty Get(Warranty request)
    {
        var warranty = new Warranty();
        if (request.Id != default(int))
        {
            warranty = Db.Id<Warranty>(request.Id);
            warranty.WarrantyOrder = ResolveService<WarrantyOrderService>().Get(new WarrantyOrder { WarrantyId = warranty.Id });
            warranty.WarrantyStatus = ResolveService<WarrantyStatusService>().Get(new WarrantyStatus { Id = warranty.StatusId });
            warranty.WarrantyNotes = ResolveService<WarrantyNoteService>().Get(new WarrantyNotes { WarrantyId = warranty.Id });
            warranty.WarrantyDialogues = ResolveService<WarrantyDialogueService>().Get(new WarrantyDialogues { WarrantyId = warranty.Id });
            warranty.WarrantyCredit = ResolveService<WarrantyCreditService>().Get(new WarrantyCredit { WarrantyId = warranty.Id });
            warranty.WarrantyPhotos = ResolveService<WarrantyPhotoService>().Get(new WarrantyPhotos { WarrantyReference = warranty.WarrantyReference });
            warranty.WarrantyReport = ResolveService<WarrantyReportService>().Get(new WarrantyReport { WarrantyId = warranty.Id });
        }

        return warranty;
    }

我已根据下面的@mythz 答案更改了ConfigureDb

    private static void ConfigureDb(Container container)
    {
        var connectionString = ConfigurationManager.ConnectionStrings["AppDb"].ConnectionString;
        container.Register<IDbConnectionFactory>(c => new OrmLiteConnectionFactory(connectionString, SqlServerDialect.Provider));
    }

该服务需要调用其他服务来填充我的Warranty 对象上的其他对象,我不确定如何改进?

【问题讨论】:

    标签: servicestack ormlite-servicestack


    【解决方案1】:

    IDbConnectionFactory 与所有连接管理器一样,是用于创建数据库连接的线程安全工厂,即它本身不是数据库连接。它应该被注册为单例。

    默认ServiceStack的IOC(Funq)默认注册为Singleton,所以正确的注册只是:

    container.Register<IDbConnectionFactory>(c =>
        new OrmLiteConnectionFactory(connectionString, SqlServerDialect.Provider));
    

    解决服务

    由于 ServiceStack 服务有可能利用托管资源,因此无论何时从另一个服务解析它们,都应该在 using 语句中使用它们,以便适当地处理它们,例如:

    using (var orders = ResolveService<WarrantyOrderService>())
    using (var status = ResolveService<WarrantyStatusService>())
    {
        var warranty = new Warranty { 
            WarrantyOrder = orders.Get(new WarrantyOrder { WarrantyId = warranty.Id }),
            WarrantyStatus = status.Get(new WarrantyStatus { 
                WarrantyId = warranty.StatusId }),
           //etc
        }       
    
        return warranty; 
    }
    

    【讨论】:

    • 那么,我是错误地使用了Db,还是没有正确设置ReuseScope
    • 是的,删除ReuseScope,因为 Funq 默认注册为 Singleton。
    • 我发现问题仍然存在,请参阅编辑@mythz
    • 这是否意味着属性注入服务没有正确处理或者容器是否处理它?例如,WarrantyOrderService(从上面)是外部服务的注入属性。
    • @jeffgabhart ServiceStack 仅处理它自己解决的服务、过滤器、依赖项等。因此,如果您自己手动解决来自 IOC 的自动装配依赖项(即 ResolveService does under-the-hood),那么您有责任处理它。
    猜你喜欢
    • 2014-02-17
    • 2015-12-25
    • 1970-01-01
    • 2012-07-24
    相关资源
    最近更新 更多