日期:2014-05-17  浏览次数:20758 次

欢迎拍砖,我在Web应用程序下,使用线程单例模式管理EF ObjectContext
为什么我要用单例模式,类似如下代码
......
Employee emp1 = model1.GetEmployeeById(10);
......
emp1.Name = "Employee Name1";
......
model2.Method(emp1);
......
mode3.Update(emp1);

如果在 model1, model2, model3 的方法中都要针对 emp1 访问数据库,则在这些模块的方法内部可能需要都 new 出 ObjectContext 对象,类似这样:
MyObjectContext db = new MyObjectContext ();
var query = 
    from obj in db.Employees
    where obj.Id = id
    select obj;

但是这样一来,这些操作就不在同一个 ObjectContext 下管理了,同时也不好使 model1, model2, model3 逻辑放在同一个事务中。

如果使用线程单例模式,也就是提供一个工厂方法,保证同一个线程调用工厂方法得到的是同一个对象,而不同的线程调用工厂方法得到的是不同对象,则处理起来就方便多了
public partial class MyObjectContext {
[ThreadStatic]
private static MyObjectContext instance;
public static MyObjectContext CurrentInstance {
get {
if (instance == null)
instance = new MyObjectContext();

return instance;
}
}
public static void ReleaseCurrent() {
if (instance != null) {
try {
instance.Dispose();
} catch { }
}

instance = null;
}
}


这样,在 model1, model2, mode3.... 这些模块里便可以使用
MyObjectContext db = MyObjectContext.CurrentInstance;
来得到当前线程的唯一实例了:
MyObjectContext db = MyObjectContext.CurrentInstance;
var query = 
    from obj in db.Employees
    where obj.Id = id
    select obj;
......

另外在 global.asax 中加上
protected void Application_EndRequest(object sender, EventArgs e) {
CBC1.Framework.Entities.DataSourceDBEntities.ReleaseCurrent();
}
当请求结束时,把当前线程的实例置空,因为IIS使用了线程池管理线程。


在我的测试程序中,模拟50个线程同时向服务器发起请求,每线程做100次请求,没有发现冲突
------解决方案--------------------
模拟50个线程?上线设置1000试试
------解决方案--------------------
测试过1000个线程同时发起请求,每线程请求10次
结果是很多请求(大约40~80个左右)因为超时而发生异常
观察CPU利用率,将近100%,但是都被 sql server 进程占用
------解决方案--------------------
null