首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >ExecuteReader需要一个开放且可用的连接。连接的当前状态为正在连接

ExecuteReader需要一个开放且可用的连接。连接的当前状态为正在连接
EN

Stack Overflow用户
提问于 2012-03-15 00:09:07
回答 2查看 178.5K关注 0票数 127

当尝试通过ASP.NET online连接到MSSQL数据库时,当两个或更多人同时连接时,我将得到以下信息:

ExecuteReader需要开放且可用的连接。连接的当前状态为正在连接。

这个站点在我的本地主机服务器上运行得很好。

这是粗略的代码。

代码语言:javascript
复制
public Promotion retrievePromotion()
{
    int promotionID = 0;
    string promotionTitle = "";
    string promotionUrl = "";
    Promotion promotion = null;
    SqlOpenConnection();
    SqlCommand sql = SqlCommandConnection();

    sql.CommandText = "SELECT TOP 1 PromotionID, PromotionTitle, PromotionURL FROM Promotion";

    SqlDataReader dr = sql.ExecuteReader();
    while (dr.Read())
    {
        promotionID = DB2int(dr["PromotionID"]);
        promotionTitle = DB2string(dr["PromotionTitle"]);
        promotionUrl = DB2string(dr["PromotionURL"]);
        promotion = new Promotion(promotionID, promotionTitle, promotionUrl);
    }
    dr.Dispose();
    sql.Dispose();
    CloseConnection();
    return promotion;
}

我可以知道可能出了什么问题吗?我该如何修复它?

编辑:别忘了,我的连接字符串和连接都是静态的。我相信这就是原因。请给我建议。

代码语言:javascript
复制
public static string conString = ConfigurationManager.ConnectionStrings["dbConnection"].ConnectionString;
public static SqlConnection conn = null;
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-03-15 01:34:47

很抱歉一开始只发表评论,但我几乎每天都会发表类似的评论,因为许多人认为将ADO.NET功能封装到DB-Class中是明智的( 10年前我也是如此)。大多数情况下,他们决定使用静态/共享对象,因为这似乎比为任何操作创建新对象更快。

从性能和故障安全性的角度来看,这都不是一个好主意。

不要在连接池的领地上偷猎

ADO-NET Connection-Pool中,ADO.NET在内部管理到DBMS的底层连接的原因很充分

在实践中,大多数应用程序只使用一种或几种不同的连接配置。这意味着在应用程序执行期间,许多相同的连接将被重复地打开和关闭。为了最大限度地降低打开连接的成本,ADO.NET使用了一种称为连接池的优化技术。

连接池减少了必须打开新连接的次数。池化程序维护物理连接的所有权。它通过为每个给定的连接配置保持一组活动连接来管理连接。每当用户对连接调用Open时,池程序都会在池中查找可用的连接。如果池连接可用,则将其返回给调用方,而不是打开新连接。当应用程序对连接调用Close时,池程序会将其返回到活动连接的池化集,而不是关闭它。一旦连接返回到池中,就可以在下一次Open调用中重用它。

因此,显然没有理由避免创建、打开或关闭连接,因为它们实际上根本不是创建、打开和关闭的。这“只”是一个标志,让连接池知道连接何时可以重用。但这是一个非常重要的标志,因为如果连接“正在使用”(连接池假定),则必须向DBMS开放一个新的物理连接,这是非常昂贵的。

所以你并没有获得性能上的提升,相反。如果达到指定的最大池大小(默认值为100),您甚至会得到异常(打开的连接太多...)。因此,这不仅会极大地影响性能,还会导致严重的错误和(不使用事务)数据转储区域。

如果您甚至使用静态连接,那么您将为试图访问此对象的每个线程创建一个锁。ASP.NET本质上是一个多线程环境。因此,这些锁有很大的机会导致最好的性能问题。实际上,迟早你会得到许多不同的异常(比如你的ExecuteReader需要一个开放的、可用的连接)。

结论

  • 根本不重用连接或任何ADO.NET对象。在VB.NET)
  • Always中创建、打开(在连接的情况下)、使用、关闭和处置它们(F.E.
  • )时,不要将它们设置为静态/共享(F.E.在一个方法中)
  • 使用using-statement来隐式地处置和关闭(在连接的情况下)

这不仅适用于连接(尽管最值得注意)。每个实现IDisposable的对象都应该被释放(using-statement最简单),尤其是在System.Data.SqlClient名称空间中。

所有这些都与封装和重用所有对象的自定义DB-Class背道而驰。这就是我评论它的原因。这只是一个问题来源。

编辑:这是您的retrievePromotion-method的一个可能实现:

代码语言:javascript
复制
public Promotion retrievePromotion(int promotionID)
{
    Promotion promo = null;
    var connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["MainConnStr"].ConnectionString;
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        var queryString = "SELECT PromotionID, PromotionTitle, PromotionURL FROM Promotion WHERE PromotionID=@PromotionID";
        using (var da = new SqlDataAdapter(queryString, connection))
        {
            // you could also use a SqlDataReader instead
            // note that a DataTable does not need to be disposed since it does not implement IDisposable
            var tblPromotion = new DataTable();
            // avoid SQL-Injection
            da.SelectCommand.Parameters.Add("@PromotionID", SqlDbType.Int);
            da.SelectCommand.Parameters["@PromotionID"].Value = promotionID;
            try
            {
                connection.Open(); // not necessarily needed in this case because DataAdapter.Fill does it otherwise 
                da.Fill(tblPromotion);
                if (tblPromotion.Rows.Count != 0)
                {
                    var promoRow = tblPromotion.Rows[0];
                    promo = new Promotion()
                    {
                        promotionID    = promotionID,
                        promotionTitle = promoRow.Field<String>("PromotionTitle"),
                        promotionUrl   = promoRow.Field<String>("PromotionURL")
                    };
                }
            }
            catch (Exception ex)
            {
                // log this exception or throw it up the StackTrace
                // we do not need a finally-block to close the connection since it will be closed implicitely in an using-statement
                throw;
            }
        }
    }
    return promo;
}
票数 240
EN

Stack Overflow用户

发布于 2019-09-29 08:06:04

几天前我发现了这个错误。

在我的例子中,这是因为我在Singleton上使用事务。

如上所述,.Net不能很好地与单例一起工作。

我的解决方案是:

代码语言:javascript
复制
public class DbHelper : DbHelperCore
{
    public DbHelper()
    {
        Connection = null;
        Transaction = null;
    }

    public static DbHelper instance
    {
        get
        {
            if (HttpContext.Current is null)
                return new DbHelper();
            else if (HttpContext.Current.Items["dbh"] == null)
                HttpContext.Current.Items["dbh"] = new DbHelper();

            return (DbHelper)HttpContext.Current.Items["dbh"];
        }
    }

    public override void BeginTransaction()
    {
        Connection = new SqlConnection(Entity.Connection.getCon);
        if (Connection.State == System.Data.ConnectionState.Closed)
            Connection.Open();
        Transaction = Connection.BeginTransaction();
    }
}

我对我的实例使用了HttpContext.Current.Items。这个类DbHelper和DbHelperCore是我自己的类

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9705637

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档