Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

ExecuteReader изисква отворена и налична връзка. Текущото състояние на връзката е Свързване

Съжалявам, че коментирам само на първо място, но публикувам почти всеки ден подобен коментар, тъй като много хора смятат, че би било разумно да се капсулира ADO.NET функционалността в DB-Class (аз също преди 10 години). Най-често те решават да използват статични/споделени обекти, тъй като изглежда по-бързо, отколкото да създадат нов обект за каквото и да е действие.

Това не е добра идея нито по отношение на производителността, нито по отношение на безопасността.

Не бракониерство на територията на Connection-Pool

Има добра причина, поради която ADO.NET вътрешно управлява основните връзки към СУБД в ADO-NET Connection-Pool:

На практика повечето приложения използват само една или няколко различни конфигурации за връзки. Това означава, че по време на изпълнение на приложението много идентични връзки ще бъдат многократно отваряни и затваряни. За да сведе до минимум разходите за отваряне на връзки, ADO.NET използва техника за оптимизиране, наречена пул на връзки.

Пулирането на връзки намалява броя пъти, през които трябва да се отварят нови връзки. Пулърът поддържа собствеността върху физическата връзка. Той управлява връзките, като поддържа активен набор от активни връзки за всяка дадена конфигурация на връзката. Всеки път, когато потребител извика Open при връзка, пулърът търси налична връзка в пула. Ако е налична обединена връзка, тя я връща на обаждащия се, вместо да отваря нова връзка. Когато приложението извика Close за връзката, пулърът го връща към обединения набор от активни връзки, вместо да го затваря. След като връзката се върне към пула, тя е готова за повторно използване при следващото отворено повикване.

Така че очевидно няма причина да избягвате създаването, отварянето или затварянето на връзки, тъй като всъщност те изобщо не се създават, отварят и затварят. Това е "само" флаг за пула за връзки, за да знае кога дадена връзка може да бъде използвана повторно или не. Но това е много важен флаг, защото ако връзката е "използвана" (пулът на връзките предполага), трябва да бъде отворена нова физическа връзка към СУБД, което е много скъпо.

Така че не получавате подобрение в производителността, а точно обратното. Ако се достигне максималният размер на пула (100 е по подразбиране), ще получите дори изключения (твърде много отворени връзки ...). Така че това не само ще повлияе значително на производителността, но и ще бъде източник на неприятни грешки и (без да използвате транзакции) зона за изхвърляне на данни.

Ако дори използвате статични връзки, вие създавате заключване за всяка нишка, която се опитва да получи достъп до този обект. ASP.NET е многонишкова среда по природа. Така че има голям шанс за тези ключалки, което в най-добрия случай причинява проблеми с производителността. Всъщност рано или късно ще получите много различни изключения (като вашият ExecuteReader изисква отворена и налична връзка ).

Заключение :

  • Изобщо не използвайте повторно връзки или обекти на ADO.NET.
  • Не ги правете статични/споделени (във VB.NET)
  • Винаги създавайте, отваряйте (в случай на връзки), използвайте, затваряйте и ги изхвърляйте там, където имате нужда (напр. в метод)
  • използвайте using-statement да изхвърли и затвори (в случай на връзки) имплицитно

Това е вярно не само за Connections (макар и най-забележимо). Всеки обект, реализиращ IDisposable трябва да бъде изхвърлен (най-простият чрез using-statement). ), още повече в System.Data.SqlClient пространство от имена.

Всичко по-горе говори срещу персонализиран DB-клас, който капсулира и използва повторно всички обекти. Това е причината да коментирам да го изхвърлям. Това е само източник на проблем.

Редактиране :Ето една възможна реализация на вашия retrievePromotion -метод:

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 [email protected]";
        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;
}


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Преобразувайте „smalldatetime“ в „datetimeoffset“ в SQL Server (T-SQL примери)

  2. Проста заявка за вземане на максимална стойност за всеки идентификатор

  3. Избройте всички бази данни от свързан сървър в SQL Server (T-SQL примери)

  4. Как да върнете низ в обратен ред с помощта на SQL Server – REVERSE()

  5. Поправете съобщение 529 „Не е позволено изрично преобразуване от тип данни int в xml“ в SQL Server