1

リクエストとスレッドの両方で、アプリケーション全体で使用されるロガークラスがあります。ロガーは、Log.Insert(文字列テキスト)ごとのデータベース挿入で構成されます。ロガーは静的クラスであり、Insertを呼び出すたびに新しいデータベースコンテキストが作成されます。Insertの呼び出しが多く、同時に多くのデータベースコンテキストが最適化に適していない可能性があります。(アプリケーション全体でSQL操作が多すぎるために、データベースがタイムアウトすることがあります。そのため、最適化が実際に必要です)。

Log.Insertsにのみ使用されるLoggerクラスの静的メンバーに単一のデータベースコンテキストを作成して保存することで、これを最適化できますか?それともこれは失敗しますか?

ロガークラスの簡略化されたバージョン。

[Table]
public class Log
{
   [Column]
   public string Text { get; set; }

   private static DataContext DatabaseContextInsert { get; set; }

   public static void Insert(string text)
   {
      if (DatabaseContextInsert == null)
      {
          DatabaseContextInsert = DataContextHelper.GetDataContext();            
      }

      var log = new Log { Text = text };          

      lock (DatabaseContextInsert)
      {
        DatabaseContextInsert.GetTable<Log>().InsertOnSubmit(log);
        DatabaseContextInsert.SubmitChanges();
      }
   }
}
4

1 に答える 1

2

静的ロガーを使用することは非常に悪い考えです。同期の問題に加えて、すべてのアイテムがデータコンテキストに永久に保持されるという問題が発生します(データコンテキストは、表示したオブジェクトを保持するのが好きです)。

多くのデータコンテキストは最適化には適さないとおっしゃっていますが、接続はおそらくすでにプールされているため(デフォルトではプールされます)、データコンテキストは実際にはそれほど「重い」ものではありません。

ログエントリを同期的に挿入する必要がない場合は、新しいログアイテムをキューにスローする(アクセスを同期する)、10秒ごとにキューを空にするワーカースレッドを作成するなど、基本的に次のようなことをしたくなるでしょう。

// adding an item
lock(queue) { queue.Enqueue(text); }


// worker code, every 10 seconds
List<string> items = new List<string>();
lock(queue) {
    while(queue.Count != 0) items.Add(items.Dequeue);
}
using(var ctx = CreateContext()) {
    foreach(var text in items) {
        ctx.Logs.InsertOnSubmit(new Log { Text = text });
    }
    ctx.SubmitChanges();
}

その場合、データベースに書き込んでいるスレッドは1つだけであり、トランザクションははるかに少なくなります。

これがオプションではなく、同期的に実行する必要がある場合は、率直に言って、いくつかのレベルを「dapper」のようなものにドロップダウンします。

using(var conn = CreateOpenConnection()) {
    conn.Execute("insert [Log]([Text]) values(@text)", new {text});
}

これにより、データコンテキストがまったく不要になり、はるかに単純になり、トランザクションが考慮から除外されます。

于 2012-06-15T07:06:58.283 に答える