[解決済み] ExecuteReader は、開いていて利用可能な Connection を必要とします。コネクションの現在の状態は、「接続中」です。
質問
ASP.NET onlineでMSSQLデータベースに接続しようとすると、2人以上が同時に接続すると以下のようになります。
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がDBMSへの接続を内部で管理するのには、それなりの理由があります。 ADO-NETコネクションプール :
実際には、ほとんどのアプリケーションは、1つまたはいくつかの異なるものを使用するだけです。 接続のためのコンフィギュレーション。つまり、アプリケーションの を実行すると、多くの同一の接続が繰り返し開かれることになります。 閉じた。ADO.NETでは、コネクションを開くコストを最小化するために コネクションプーリングと呼ばれる最適化技術。
接続プーリングは、新しい接続の回数を減らすことができます。 を開かなければならない。プーラーは物理的な所有権を維持します。 コネクションを使用します。接続を管理するために、アクティブな接続のセットを維持します。 接続の構成に応じた ユーザーが プーラーは、接続のオープンを呼び出すと、利用可能な接続を探します。 のコネクションをプール内に保持する。プールされた接続が利用可能な場合、プールされた接続が利用可能な場合 は、新しい接続を開く代わりに、その接続を呼び出し元に返します。呼び出した側が アプリケーションは、接続のクローズを呼び出すと、プーラーはその接続を を閉じるのではなく、プールされた有効な接続の集合を閉じる。一度 接続がプールに戻されると、その接続を再利用する準備が整います。 次の Open 呼び出し
つまり、コネクションの作成、オープン、クローズを避ける理由は何もないのです。これは、コネクションプールがコネクションを再利用できるかどうかを知るためのフラグに過ぎません。しかし、これは非常に重要なフラグです。なぜなら、もし接続が使用中であれば(接続プールはそう仮定します)、新しい物理接続をDBMSにオープンしなければならず、これは非常にコストがかかるからです。
つまり、パフォーマンスが向上するどころか、その逆になってしまうわけです。もし、指定された最大プールサイズ(デフォルトは100)に達すると、例外(開いている接続が多すぎる...)が発生することさえあります。つまり、これはパフォーマンスに多大な影響を与えるだけでなく、厄介なエラーの原因となり、(トランザクションを使用しない場合)データダンプエリアとなります。
静的な接続を使用している場合、このオブジェクトにアクセスしようとするすべてのスレッドに対してロックを作成することになります。ASP.NETは元々マルチスレッド環境です。そのため、これらのロックが発生する可能性が高く、パフォーマンス上の問題が発生します。実際、遅かれ早かれ、さまざまな例外が発生するでしょう。 ExecuteReader は、開いていて利用可能な接続を必要とします。 ).
結論 :
- コネクションやADO.NETオブジェクトを一切再利用しないこと。
- 静的/共有にしない(VB.NETの場合)
- 作成、オープン(コネクションの場合)、使用、クローズ、ディスポは必ず必要な場所(メソッド内など)で行ってください。
-
を使用します。
using-statement
暗黙のうちに廃棄・閉鎖すること。
これは、Connectionsに限ったことではありません(もっとも顕著ですが)。を実装しているすべてのオブジェクトは
IDisposable
を廃棄する必要があります(最もシンプルな方法は
using-statement
) の中で、さらに
System.Data.SqlClient
という名前空間があります。
以上のことから、すべてのオブジェクトをカプセル化して再利用するカスタムDB-Classに反対していることがわかります。それが、私がゴミ箱に入れるようにコメントした理由です。あくまで問題発生源です。
編集
: 以下は、あなたの
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 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;
}
関連
-
[解決済み】ASP.NET Core Dependency Injectionのエラーです。アクティブ化しようとしているときに、タイプのサービスを解決できません。
-
[解決済み】パディングが無効で、削除できない?
-
[解決済み】ソケットのアドレス(プロトコル/ネットワークアドレス/ポート)は、通常1つしか使用できない?
-
[解決済み】トランスポート接続からデータを読み取れない:既存の接続は、リモートホストによって強制的に閉じられました。
-
[解決済み】非静的メソッドはターゲットを必要とする
-
[解決済み】リソースの読み込みに失敗した:ステータス500(内部サーバーエラー)のサーバーの応答)
-
[解決済み] 'IEnumerable<SelectListItem>' 型の ViewData アイテムで、キーが国であるものは存在しない。
-
[解決済み】EF 5 Enable-Migrations : アセンブリにコンテキストタイプが見つかりませんでした
-
[解決済み] EntityTypeにキーが定義されていないエラー
-
[解決済み】 C# 条件演算子エラー 代入、call、increment、decrement、await、new object 式のみ文として使用可能です。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] エンティティタイプ ApplicationUser は、現在のコンテキストのモデルの一部ではありません。
-
[解決済み】バックスラッシュを含むパス文字列のエスケープシーケンスが認識されない件
-
[解決済み】クロススレッド操作が有効でない。作成されたスレッド以外のスレッドからアクセスされたコントロール
-
[解決済み】C# - パスに不正な文字がある場合
-
[解決済み】"指定されたパスのフォーマットはサポートされていません。"
-
[解決済み】値をNULLにすることはできません。パラメータ名:source
-
[解決済み】ファイルへの読み書きの際に共有違反のIOExceptionが発生する C#
-
[解決済み】エラー「必要なフォーマルパラメータに対応する引数が与えられていない」を解決する?
-
[解決済み】データが存在しないのに読み込もうとする試みが無効である
-
[解決済み】Nullableオブジェクトは値を持たなければならない?