При попытке подключиться к базе данных MSSQL через ASP.NET онлайн, я получу следующее, когда два или более человека подключатся одновременно:
ExecuteReader требует открытого и доступного соединения. Текущее состояние подключения - Connecting.
Сайт отлично работает на моем сервере localhost.
Это приблизительный код.
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;
c#
.net
sql-server
ado.net
database-connection
Го Хун Лим
источник
источник
conString
ничего не добавляет с точки зрения производительности, так как она в любом случае кешируется по умолчанию (как и каждое значение конфигурации для текущего приложения).Ответы:
Извините, что только комментирую в первую очередь, но я публикую почти каждый день аналогичный комментарий, поскольку многие люди думают, что было бы разумно инкапсулировать функциональность ADO.NET в DB-Class (я тоже 10 лет назад). В основном они решают использовать статические / общие объекты, поскольку это кажется быстрее, чем создание нового объекта для любого действия.
Это не лучшая идея ни с точки зрения производительности, ни с точки зрения отказоустойчивости.
Не переманивайте на территории пула подключений
Есть веская причина, по которой ADO.NET внутренне управляет базовыми соединениями с СУБД в пуле соединений ADO-NET :
Итак, очевидно, что нет причин избегать создания, открытия или закрытия соединений, поскольку на самом деле они вообще не создаются, не открываются и не закрываются. Это «всего лишь» флаг для пула соединений, который определяет, можно ли повторно использовать соединение. Но это очень важный флаг, потому что, если соединение «используется» (предполагает пул соединений), новое физическое соединение должно быть открытым для СУБД, что очень дорого.
Таким образом, вы не получаете улучшения производительности, а наоборот. Если будет достигнут указанный максимальный размер пула (по умолчанию 100), вы даже получите исключения (слишком много открытых подключений ...). Таким образом, это не только сильно повлияет на производительность, но и станет источником неприятных ошибок и (без использования транзакций) области сброса данных.
Если вы даже используете статические соединения, вы создаете блокировку для каждого потока, пытающегося получить доступ к этому объекту. ASP.NET по своей природе является многопоточной средой. Так что есть отличная возможность для этих блокировок, которые в лучшем случае вызывают проблемы с производительностью. На самом деле рано или поздно вы получите много разных исключений (например, вашему ExecuteReader требуется открытое и доступное соединение ).
Вывод :
using-statement
для удаления и закрытия (в случае Connections) неявноЭто верно не только для Connections (хотя это наиболее заметно). Каждый реализующий объект
IDisposable
должен быть удален (проще всегоusing-statement
), тем более вSystem.Data.SqlClient
пространстве имен.Все вышесказанное говорит против специального класса DB, который инкапсулирует и повторно использует все объекты. Вот почему я решил выбросить его в корзину. Это только источник проблемы.
Изменить : вот возможная реализация вашего
retrievePromotion
метода:источник
Я поймал эту ошибку несколько дней назад.
В моем случае это было потому, что я использовал транзакцию на синглтоне.
.Net плохо работает с Singleton, как указано выше.
Мое решение было таким:
Для своего экземпляра я использовал HttpContext.Current.Items. Этот класс DbHelper и DbHelperCore - мой собственный класс
источник