不允许启动新事务,因为有其他线程正在该会话中运行(ef并发错误处理之一)

本文介绍了一个使用Entity Framework进行并发更新时遇到的错误:“不允许启动新事务,因为有其他线程正在该会话中运行”。通过分析问题原因及提供解决方案,帮助读者理解并发环境下如何正确更新数据库。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近项目上线试运行过程中,总是遇到各种莫名其妙的问题,纠结了很久,今天就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方法去增加记录,而不是修改记录。或者通过用存储过程,将数据重新刷进表中,但是这样就缺乏实时性。


真是蛋痛的并发!以后再想想,看看有没有其他的解决办法吧。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值