programing

ExecuteReader를 사용하려면 열려 있고 사용 가능한 연결이 필요합니다.연결의 현재 상태는 연결 중입니다.

instargram 2023. 5. 17. 22:26
반응형

ExecuteReader를 사용하려면 열려 있고 사용 가능한 연결이 필요합니다.연결의 현재 상태는 연결 중입니다.

ASP.NET 온라인을 통해 MSSQL 데이터베이스에 연결하려고 하면 두 명 이상이 동시에 연결할 때 다음 메시지가 나타납니다.

ExecuteReader를 사용하려면 열려 있고 사용 가능한 연결이 필요합니다.연결의 현재 상태는 연결 중입니다.

내 로컬 호스트 서버에서 사이트가 정상적으로 작동합니다.

이것은 대략적인 코드입니다.

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

무엇이 잘못되었는지 그리고 어떻게 고치는지 알 수 있을까요?

편집: 제 연결 문자열과 연결이 모두 정적인 것을 잊지 마십시오.저는 이것이 이유라고 생각합니다.조언 부탁드립니다.

public static string conString = ConfigurationManager.ConnectionStrings["dbConnection"].ConnectionString;
public static SqlConnection conn = null;

애초에 댓글만 달아서 죄송합니다만, ADO.NET 기능을 DB-Class(10년 전의 저)로 캡슐화하는 것이 현명할 것이라고 생각하는 사람들이 많아서 거의 매일 비슷한 댓글을 올립니다.대부분 정적/공유 개체를 사용하기로 결정하는데, 이는 어떤 작업에 대해서도 새 개체를 만드는 것보다 더 빠른 것처럼 보이기 때문입니다.

그것은 성능 측면에서도, 고장 안전 측면에서도 좋은 생각이 아닙니다.

Connection-Pool 영역을 밀렵하지 않음

ADO.NET이 ADO-NET Connection-Pool에서 DBMS에 대한 기본 연결을 내부적으로 관리하는 데는 충분한 이유가 있습니다.

실제로 대부분의 응용 프로그램은 연결에 하나 또는 몇 가지 다른 구성만 사용합니다.즉, 응용프로그램 실행 중에 많은 동일한 연결이 반복적으로 열리고 닫힙니다.ADO.NET은 연결을 여는 비용을 최소화하기 위해 연결 풀링이라는 최적화 기술을 사용합니다.

연결 풀링은 새 연결을 열어야 하는 횟수를 줄입니다.풀러는 물리적 연결의 소유권을 유지합니다.지정된 각 연결 구성에 대해 활성 연결 집합을 유지하여 연결을 관리합니다.사용자가 연결에서 열기를 호출할 때마다 풀러는 풀에서 사용 가능한 연결을 찾습니다.풀링된 연결을 사용할 수 있는 경우 새 연결을 여는 대신 해당 연결을 호출자에게 반환합니다.응용 프로그램이 연결에서 닫기를 호출하면 풀러는 해당 연결을 닫는 대신 풀링된 활성 연결 집합으로 반환합니다.연결이 풀로 반환되면 다음 열기 호출 시 다시 사용할 수 있습니다.

따라서 연결은 실제로 만들어지거나 열리거나 닫히는 것이 아니기 때문에 생성, 열거나 닫히는 것을 피할 이유가 없습니다.이것은 연결 풀이 연결을 재사용할 수 있는지 여부를 알 수 있는 "전용" 플래그입니다.그러나 연결이 "사용 중"(연결 풀에서 가정)인 경우 DBMS에 새로운 물리적 연결을 열어야 하기 때문에 매우 비용이 많이 들기 때문에 이 플래그는 매우 중요합니다.

따라서 성능이 향상되는 것이 아니라 그 반대입니다.지정된 최대 풀 크기(기본값 100)에 도달하면 예외(열린 연결이 너무 많음...)가 발생할 수도 있습니다.따라서 이는 성능에 큰 영향을 미칠 뿐만 아니라 심각한 오류의 원인이 되고 (트랜잭션을 사용하지 않고) 데이터 덤프 영역이 될 수 있습니다.

정적 연결을 사용하는 경우에도 이 개체에 액세스하려는 모든 스레드에 대해 잠금이 만들어집니다. ASP.NET은 기본적으로 멀티스레딩 환경입니다.따라서 성능 문제를 유발하는 이러한 잠금 장치가 있을 가능성이 높습니다.실제로 조만간 다양한 예외가 발생할 것입니다(예: ExecuteReader에 사용 가능한 개방형 연결이 필요한 경우).

결론:

  • 연결이나 ADO.NET 개체를 재사용하지 마십시오.
  • VB.NET에서 정적/공유 상태로 만들지 마십시오.
  • 항상 생성, 열기(연결의 경우), 사용, 닫기 및 필요한 곳에 폐기(예: 방법)
  • 를 사용하여 암시적으로 처리하고 닫습니다(연결의 경우).

이는 연결에만 해당되는 것이 아닙니다(가장 눈에 띄지만).구현하는 모든 객체는 (가장 단순하게) 배치되어야 하며, 더욱 더System.Data.SqlClient네임스페이스입니다.

위의 모든 내용은 모든 개체를 캡슐화하고 재사용하는 사용자 지정 DB-Class에 반대합니다.그것이 제가 그것을 버리라고 댓글을 단 이유입니다.그것은 단지 문제의 근원일 뿐입니다.


편집: 가능한 구현 방법은 다음과 같습니다.retrievePromotionfilename:

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 implicitly in an using-statement
                throw;
            }
        }
    }
    return promo;
}

저는 며칠 전에 이 오류를 발견했습니다.

저의 경우에는 싱글톤에서 트랜잭션을 사용하고 있었기 때문입니다.

.Net은 위에서 언급한 것처럼 Singleton과 잘 작동하지 않습니다.

제 해결책은 다음과 같습니다.

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를 사용했습니다.현재의.제 경우를 위한 항목.이 클래스 DbHelper 및 DbHelperCore는 나만의 클래스입니다.

언급URL : https://stackoverflow.com/questions/9705637/executereader-requires-an-open-and-available-connection-the-connections-curren

반응형