我有一个记录器类,在我的应用程序中使用,包括请求和线程。记录器由每个Log.Insert(字符串文本)的数据库插入组成。记录器是一个静态类,并为每次调用Insert创建一个新的数据库上下文。可能会有很多对Insert的调用,并且许多数据库上下文同时不适合优化。 (我有时会因为整个应用程序中的sql操作太多而导致数据库超时 - 因此确实需要进行优化。)
可以通过在Logger类的静态成员中创建和存储单个数据库上下文来优化它,该成员仅用于Log.Inserts吗?或者这会失败吗?
记录器类的简化版本;
[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();
}
}
}
答案 0 :(得分: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();
}
然后只有一个线程正在写入数据库,并且您的事务少得多。
如果这个不是一个选项,并且你需要同步进行,那么坦率地说,我会将一些级别下降到类似“dapper”的东西,即
using(var conn = CreateOpenConnection()) {
conn.Execute("insert [Log]([Text]) values(@text)", new {text});
}
在所有中删除了对数据上下文的需求,简单得多,并且不考虑事务。