C#で作業した最後のプロジェクトでは、dbに接続するために多くのモデルを使用しました。エンティティフレームワーク、私はdbの接続のための静的クラスを作成したが、私は10-15以上の要求が一緒に来るとき私はエラーを与えるために接続の開閉に問題があったそしてすべての静的メソッドとクラスを削除しました。
今知りたい
接続するための最良のモデルは何ですか?
例えば私はSMS送信者のWebパネルに取り組んで、私は毎秒100KのSMSを送信する必要があります、これらのSMSは他人と収集し、すべてのパッケージは1〜20SMSを持つパッケージを作るパッケージ私はこれらの手順を実行する必要があります。
すべてのステップと、ログ、ユーザーインターフェース、監視ウィジェットなど、他にも必要なことはたくさんあります。このトランザクションをすべて実行するには、DB接続が必要です。
さて、DBに接続するための最良のモデルは何ですか?人間の要求によって、またはスレッド要求によって、またはすべての単一のトランザクションによって。
1. Should i close it after every query?
.Netはあなたに代わってそれを処理するので、それを処理させます。それはガベージコレクタのタスクです。オブジェクトを手動で破棄しても構いません。これはJon Skeetによる良い答えです。https://stackoverflow.com/a/1998600/544283。しかしあなたは使用することができますusing(IDisposable){ }
GCに強制的に実行させるステートメントこれは、リソースの再割り当てに関する素晴らしい記事です。http://www.codeproject.com/Articles/29534/IDisposable-What-Your-Mother-Never-Told-You-About。
2. A connection in static class is good?
しないデータコンテキストを静的にするデータコンテキストはではないスレッドセーフまたはコンカレントセーフ。
3. Is there a good design pattern for this problem?
Belogixが依存性注入と作業単位パターンが優れていると述べたように、実際にはエンティティフレームワークです作業単位自体です。 DIとUoWは少し過大評価されていますが、IoCコンテナを初めて扱う場合は実装が簡単ではありません。その場合は、Ninjectを推奨します。もう1つのことは、テストを実行しないのであれば本当にDIを必要としないということです。これらのパターンの素晴らしい点は、切り離すことです。
手短に言うと、コードに対してテストを実行するのであれば、これらのパターンを試してください。そうでなければ、私はあなたがあなたが望むサービスの間であなたがあなたのデータコンテキストをどのように共有できるかについての例をあなたに提供しています。これがあなたの4番目の質問に対する答えです。
4. What is the best method for making database connection (static, per request)?
あなたのコンテキストサービス:
public class FooContextService {
private readonly FooContext _ctx;
public FooContext Context { get { return _ctx; } }
public FooContextService() {
_ctx = new FooContext();
}
}
他のサービス:
public class UnicornService {
private readonly FooContext _ctx;
public UnicornService(FooContextService contextService) {
if (contextService == null)
throw new ArgumentNullException("contextService");
_ctx = contextService.Context;
}
public ICollection<Unicorn> GetList() {
return _ctx.Unicorns.ToList();
}
}
public class DragonService {
private readonly FooContext _ctx;
public DragonService(FooContextService contextService) {
if (contextService == null)
throw new ArgumentNullException("contextService");
_ctx = contextService.Context;
}
public ICollection<Dragon> GetList() {
return _ctx.Dragons.ToList();
}
}
コントローラ:
public class FantasyController : Controller {
private readonly FooContextService _contextService = new FooContextService();
private readonly UnicornService _unicornService;
private readonly DragonService _dragonService;
public FantasyController() {
_unicornService = new UnicornService(_contextService);
_dragonService = new DragonService(_contextService);
}
// Controller actions
}
考え直し(ほとんど編集): エンティティのプロキシを作成しないために遅延ロードを行わないようにコンテキストが必要な場合は、次のようにコンテキストサービスをオーバーロードすることができます。
public class FooContextService {
private readonly FooContext _ctx;
public FooContext Context { get { return _ctx; } }
public FooContextService() : this(true) { }
public FooContextService(bool proxyCreationEnabled) {
_ctx = new FooContext();
_ctx.Configuration.ProxyCreationEnabled = proxyCreationEnabled;
}
}
注意:
編集:
最初に読むもの:
これを成し遂げる:
(_context as IObjectContextAdapter).ObjectContext.Connection.Open();
これは素晴らしい記事です接続とトランザクションの管理。
エンティティフレームワークは、Connectionプロパティを通じてEntityConnectionを公開します。として読む:public sealed class EntityConnection : DbConnection
。
接続を管理するための考慮事項:(前のリンクから引用)
それが役に立てば幸い。
using(IDisposable){ }
GCに強制的に実行させるステートメント」不正確でもある - usingステートメントはGCに何もさせません。 - default.kramer"Don't bother disposing your objects manually"
:誰がしますか各オブジェクトを手動で配置しますか? GCが自動的に何もしない各オブジェクトを手動で破棄しても、GCはリソースを解放する方法とタイミングについて非常に賢いと言っていました。そして"use the using{} statement to force the GC to do it's work"
:あなたはそれが内の資源であることを暗示しているかusing
ブロックは呼び出しませんDispose
スコープが終了したときのそのリソースのメソッドもしそうなら、なぜ実装する必要がありますIDisposable
を使用する場合using
ステートメント?これを反映するように回答を変更します。 - EstebanIDisposable
。 Ausing
通話をブロックするDispose
; GCはファイナライザを呼び出します。一般的な「セーフティネット」。ファイナライザに次のことを保証させることです。Dispose
と呼ばれていましたが、行儀の良いアプリケーションではこのセーフティネットは必要ないはずです - すべてIDisposables
GCの関与なしに処分する必要があります。 - default.kramer
あなたの質問に対する答え:
閉じてください。 .NETは、内部で接続プールを行います。
それを作成してください。毎回using(Connection conn = new ....)を使用してください。このようにして、.NETプーリング機構を最大限に活用できます。
.NET ThreadPool(または独自のカスタムスレッド)を使用し、ThreadPoolを10スレッドのみを並列に使用するように定義し、次々に作業項目をエンキューすることができます。このようにすれば、10回以上の接続が同時に使用されることはなくなり、おそらくより速く動作するでしょう。 カスタムスレッドプールの詳細:カスタムThreadPoolの実装
インスタンスごと
これが私のアーキテクチャーの提案です。
保留中のSMSを送信するためのデータベーステーブル(キュー)を作成します。
各行にはSMS +現在のステータスに必要なすべての情報が含まれます。
ワーカープロセス、おそらくこのテーブルを絶えずサンプリングするwindowsサービスを作成しましょう - たとえば、5秒ごとにしましょう。 status = '送信待ち'のTOP〜20のSMSを選択します(intで表す必要があります)。ステータスを「送信中」に更新します
各SMSは、Windowsサービス側のカスタムスレッドプールを使用して送信されます。
プロセスの最後に、すべての処理されたSMSステータスはCTE(共通テーブル式を使用して '完了'に更新されます。 '一括更新'を実行するために処理されたすべてのSMS行IDを含むCTEを送信できます。 「完了」ステータスになります。
ステータス更新ストアドプロシージャを 'getpending'と同じものにすることができます。このようにして、ロックなしでupdate-for-updateを実行し、データベースをより高速に動作させることができます。
このようにして、複数のプロセッササービスを実行させることができます(ただし、その後nolockを解放する必要があります)。
できるだけ多くのロックを避けるようにしてください。
ところで、保留中のSMSテーブルに行を追加するだけで、システム内の任意の場所からSMSを送信できるため、これも有効です。
そしてもう1つ、フードの下ではあまりにも多くのことが起こっているので、このためにエンティティフレームワークを使用することはお勧めしません。この種のタスクに必要なのは、3〜4個のストアード・プロシージャーを呼び出すだけです。それだけです。たぶんを見てくださいDapper-dot-NET - 非常に軽量のMicroDalフレームワークで、ほとんどの場合、EF(Entity Framework)の10倍以上の速度で動作します。
私は要求ごとのスケールが最も良いと思います。スレッドセーフな接続プールを使用して、接続範囲を作業単位と一致させます。トランザクションの振る舞いと作業単位を担当するサービスが接続をチェックアウトし、それを使用して、作業単位がコミットまたはロールバックされたときにプールに戻すようにします。
更新:
ステータス更新をコミットするのに10〜12秒?あなたは他の何か悪いことをしました。書かれているあなたの質問は適切な答えを提供するのに十分ではありません。
毎日のNASDAQのボリューム1.3Bトランザクションであり、8時間の日には毎秒約45Kトランザクションになります。あなたのボリュームはナスダックの2倍です。もしあなたが一つのマシンでそれをやろうとしているなら、私はNASDAQが複数のサーバーを使っていると言うでしょう。
ACIDを使ってそのステータスを更新しなくてもできるかどうかも疑問に思います。結局、スターバックスは2フェーズコミットを使用しません。たぶんもっと良い解決策は、それらが送られた後にあなたができるときにそれらの状態を更新するためにブロッキングキューを持つプロデューサー/コンシューマーパターンを使うことでしょう。