Lors de la tentative de connexion à la base de données MSSQL via ASP.NET en ligne, j'obtiendrai ce qui suit lorsque deux ou plusieurs personnes se connectent simultanément:
ExecuteReader nécessite une connexion ouverte et disponible. L'état actuel de la connexion est Connexion.
Le site fonctionne bien sur mon serveur localhost.
Ceci est le code approximatif.
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;
}
Puis-je savoir ce qui a pu mal tourner et comment puis-je y remédier?
Edit: Ne pas oublier, ma chaîne de connexion et ma connexion sont toutes deux en statique. Je crois que c'est la raison. S'il vous plaît donnez votre avis.
public static string conString = ConfigurationManager.ConnectionStrings["dbConnection"].ConnectionString;
public static SqlConnection conn = null;
c#
.net
sql-server
ado.net
database-connection
Guo Hong Lim
la source
la source
conString
n'ajoute rien en termes de performances car il est de toute façon mis en cache par défaut (comme chaque valeur de configuration pour l'application actuelle).Réponses:
Désolé de ne commenter qu'en premier lieu, mais je poste presque tous les jours un commentaire similaire car beaucoup de gens pensent qu'il serait judicieux d'encapsuler la fonctionnalité ADO.NET dans une DB-Class (moi aussi il y a 10 ans). La plupart du temps, ils décident d'utiliser des objets statiques / partagés car cela semble être plus rapide que de créer un nouvel objet pour toute action.
Ce n'est ni une bonne idée en termes de performances ni en termes de sécurité.
Ne pas braconner sur le territoire du Connection-Pool
Il y a une bonne raison pour laquelle ADO.NET gère en interne les connexions sous-jacentes au SGBD dans le pool de connexions ADO-NET :
Il n'y a donc évidemment aucune raison d'éviter de créer, d'ouvrir ou de fermer des connexions car elles ne sont en fait pas créées, ouvertes et fermées du tout. Il s'agit "uniquement" d'un indicateur permettant au pool de connexions de savoir quand une connexion peut être réutilisée ou non. Mais c'est un indicateur très important, car si une connexion est "en cours d'utilisation" (le pool de connexions suppose), une nouvelle connexion physique doit être ouverte au SGBD, ce qui est très coûteux.
Vous n'obtenez donc aucune amélioration des performances, mais le contraire. Si la taille maximale du pool spécifiée (100 est la valeur par défaut) est atteinte, vous obtiendrez même des exceptions (trop de connexions ouvertes ...). Cela aura donc non seulement un impact considérable sur les performances, mais sera également une source d'erreurs désagréables et (sans utiliser de transactions) une zone de vidage de données.
Si vous utilisez même des connexions statiques, vous créez un verrou pour chaque thread essayant d'accéder à cet objet. ASP.NET est un environnement multithreading par nature. Il y a donc une grande chance pour ces verrous qui causent au mieux des problèmes de performances. En fait, tôt ou tard, vous obtiendrez de nombreuses exceptions différentes (comme votre ExecuteReader nécessite une connexion ouverte et disponible ).
Conclusion :
using-statement
pour supprimer et fermer (en cas de connexions) implicitementC'est vrai non seulement pour les connexions (bien que le plus notable). Chaque objet implémentant
IDisposable
doit être supprimé (le plus simple parusing-statement
), d'autant plus dans l'System.Data.SqlClient
espace de noms.Tout ce qui précède va à l'encontre d'une DB-Class personnalisée qui encapsule et réutilise tous les objets. C'est la raison pour laquelle j'ai commenté pour le détruire. Ce n'est qu'une source de problème.
Edit : Voici une implémentation possible de votre
retrievePromotion
-method:la source
J'ai attrapé cette erreur il y a quelques jours.
Dans mon cas, c'était parce que j'utilisais une transaction sur un Singleton.
.Net ne fonctionne pas bien avec Singleton comme indiqué ci-dessus.
Ma solution était la suivante:
J'ai utilisé HttpContext.Current.Items pour mon instance. Cette classe DbHelper et DbHelperCore est ma propre classe
la source