在 ASP.NET 中管理 DataContext 的好方法? SqlException:服务器无法恢复事务
我们使用以下类为每个请求创建一个 Linq2Sql DataContext:
public static class DataContextManager
{
private const string HTTPCONTEXT_KEY = "DataContextManagerKey";
private static CompanyDataContext _staticContext; //when there's no HttpContext (in test/debug situations).
public static CompanyDataContext Context
{
get
{
if (_Context == null)
{
_Context = NewContext();
}
return _Context;
}
}
private static CompanyDataContext _Context
{
get
{
return (CompanyDataContext)(HttpContext.Current != null ? HttpContext.Current.Items[HTTPCONTEXT_KEY] : _staticContext);
}
set
{
if (HttpContext.Current != null)
{
HttpContext.Current.Items[HTTPCONTEXT_KEY] = value;
}
else
{
DataContextManager._staticContext = value;
}
}
}
public static void Dispose()
{
CompanyDataContext context = _Context;
if (context != null)
{
if (Config.Instance.TestMode) context.Log.WriteLine("--- DISPOSING DATACONTEXT ---");
context.Dispose();
_Context = null;
}
}
public static CompanyDataContext NewContext()
{
CompanyDataContext db = new CompanyDataContext();
db.CommandTimeout = Config.SQL_COMMAND_TIMEOUT;
if (Config.Instance.TestMode)
{
db.Log = new ConsoleTextWriter();
db.Log.WriteLine("--- CREATING NEW DATACONTEXT ---");
}
return db;
}
}
在 Global.asax 中:
protected void Application_EndRequest(Object sender, EventArgs e)
{
DataContextManager.Dispose();
}
我问的原因是我们每天突然收到一两次随机的“SqlException:服务器无法恢复事务”异常使用曾经完美运行的代码。异常发生后,我们会收到许多其他异常,直到重新启动 Web 应用程序为止。有人见过这种行为吗?
我们正在 IIS 6 上运行带有 SQL Server 2005 的 ASP .Net 2.0。
更新:
这样就没有其他人犯和我们一样的可怕错误了:
事实证明,一些工作线程也使用了 DataContext,但它们当然没有 HttpContext获取 _staticContext(DataContextManager 中的一项功能,仅在测试时使用)。我们重写了工作线程中的代码,以确保每个线程都有一个 DataContext 并在完成后对其进行处置。到目前为止,一切都已经持续了两周了:)
We create one Linq2Sql DataContext for every request using the following class:
public static class DataContextManager
{
private const string HTTPCONTEXT_KEY = "DataContextManagerKey";
private static CompanyDataContext _staticContext; //when there's no HttpContext (in test/debug situations).
public static CompanyDataContext Context
{
get
{
if (_Context == null)
{
_Context = NewContext();
}
return _Context;
}
}
private static CompanyDataContext _Context
{
get
{
return (CompanyDataContext)(HttpContext.Current != null ? HttpContext.Current.Items[HTTPCONTEXT_KEY] : _staticContext);
}
set
{
if (HttpContext.Current != null)
{
HttpContext.Current.Items[HTTPCONTEXT_KEY] = value;
}
else
{
DataContextManager._staticContext = value;
}
}
}
public static void Dispose()
{
CompanyDataContext context = _Context;
if (context != null)
{
if (Config.Instance.TestMode) context.Log.WriteLine("--- DISPOSING DATACONTEXT ---");
context.Dispose();
_Context = null;
}
}
public static CompanyDataContext NewContext()
{
CompanyDataContext db = new CompanyDataContext();
db.CommandTimeout = Config.SQL_COMMAND_TIMEOUT;
if (Config.Instance.TestMode)
{
db.Log = new ConsoleTextWriter();
db.Log.WriteLine("--- CREATING NEW DATACONTEXT ---");
}
return db;
}
}
And in Global.asax:
protected void Application_EndRequest(Object sender, EventArgs e)
{
DataContextManager.Dispose();
}
The reason why I'm asking is that we're suddenly getting random "SqlException: Server failed to resume the transaction" exceptions once or twice every day with code that used to work perfectly. After the exception we get a lot of other exceptions until we restart the web application. Anyone seen this behaviour before?
We're running ASP .Net 2.0 with SQL server 2005 on IIS 6.
UPDATE:
Just so no one else does the same horrible mistake as we did:
It turned out that some worker threads also used the DataContext but with no HttpContext they of course got the _staticContext (a feature in DataContextManager only to be used when testing). We rewrote the code in the worker threads to make sure one DataContext per thread and disposing it when done. And so far everything has worked for 2 weeks :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是一个糟糕的模式。首先,您永远不应该拥有一个实现 IDisposable 的静态数据上下文,这样一个线程可以尝试使用该上下文,而另一个线程正在处理它以及许多其他潜在问题。每个 http 请求一个数据上下文也不好,数据上下文被设计用于单个事务,然后被丢弃。如果您检索更新/插入/删除并使用相同的上下文进行检索,则会出现问题,第二次检索不会反映更新/插入/删除的更改。删除静态上下文,让 Context 属性每次都返回一个新的上下文。您仍然可以在请求结束时处理所有内容,方法是将它们全部粘贴到 List 属性中并迭代它。
This is a bad pattern. First you should never have a static data context it implements IDisposable so one thread could try to use the context while another is disposing of it plus many other potential problems. One data context per http request is no good either, data contexts are designed to be used for a single transaction then disposed of. You get problems if you retrieve update/insert/delete and retrieve using the same context, the second retrieve does not reflect the changes of the update/insert/delete. Remove the static context and just have the Context property return a new context every time. You could still dispose of the all at the end of a request by sticking them all in a List property and iterating through it.