最近项目上线试运行过程中,总是遇到各种莫名其妙的问题,纠结了很久,今天就ef出现的“不允许启动新事务,因为有其他线程正在该会话中运行”这个错误,记录自己的解决方法。
当遇到这个问题的时候,在网上搜了很久,在这里还是要鄙视一下那些转载又不写出处的站长。
问题发现:
开始一直以为是数据库或者服务器的问题,因为用的是虚拟空间,很多设置没有办法改变。后来加入站长统计之后,发现pv量居然在200左右,突然意识到有可能是并发造成的。于是自己写了一段测试代码,该段代码的作用是模拟用户阅读新闻的时候,使新闻的阅读次数加1(只是改变字段的值,而不是新增一条浏览记录再去统计阅读次数)。代码如下:
public partial class WebForm1 : System.Web.UI.Page
{
delegate bool MyDelegate(Read info);
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
ReadInfo ri = new ReadInfo ();
Read rad1 = ri.Get(1);
rad1.ReadTime += 1;
Read rad2 = ri.Get(1);
rad2.ReadTime += 1;
MyDelegate myDelegate = new MyDelegate(ri.Update);
myDelegate.BeginInvoke(rad1, null, null);
myDelegate.BeginInvoke(rad2, null, null);
Thread.Sleep(300);
}
}
}
public class ReadInfo
{
testEntities mytest = new testEntities();
public ReadInfo()
{
mytest.Read.MergeOption = System.Data.Objects.MergeOption.OverwriteChanges;
mytest.Read.EnablePlanCaching = false;
}
public Read Get(int Id)
{
return mytest.Read.SingleOrDefault(c => c.myId == Id);
}
public bool Update(Read Info)
{
int Result = 0;
if (mytest.Read.Count(c => c.myId == Info.myId) == 1)
{
Thread.Sleep(100);
Result = mytest.SaveChanges();
}
return Result > 0;
}
}
F10跟踪代码运行就报以下错误:
于是监控以下代码发现并发产生的时候,第一次是Modified,第二次却是Unchanged,所以当运行第二次更新的时候,则报错“不允许启动新事务,因为有其他线程正在该会话中运行”
所以最后解决此问题的方法就是将Update的代码改成:
public bool Update(Read Info)
{
int Result = 0;
if (mytest.Read.Count(c => c.myId == Info.myId) == 1)
{
if (Info.EntityState == System.Data.EntityState.Modified)
{
mytest.Refresh(RefreshMode.ClientWins, Info);
Thread.Sleep(100);
Result = mytest.SaveChanges();
}
}
return Result > 0;
}
虽然这样解决可以保证程序的稳定性,但是当并发发生的时候,阅读次数就不能+1了。不过阅读次数这个属性对于网站的数据而言并不是很重要,所以先这么解决着吧。如果是比较重要的属性,建议还是通过add方法去增加记录,而不是修改记录。或者通过用存储过程,将数据重新刷进表中,但是这样就缺乏实时性。
真是蛋痛的并发!以后再想想,看看有没有其他的解决办法吧。