博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
EF 多线程TransactionScope事务异常"事务(进程 ID 58)与另一个进程被死锁在 锁 资源上,并且已被选作死锁牺牲品。请重新运行该事务。"
阅读量:4287 次
发布时间:2019-05-27

本文共 2976 字,大约阅读时间需要 9 分钟。

一、在使用EF的TransactionScope事务时,如果多线程程序,经常会抛出如下异常

{"事务(进程 ID 58)与另一个进程被死锁在 锁 资源上,并且已被选作死锁牺牲品。请重新运行该事务。"}

同一个TransactionScope逻辑操作事务在多线程中启动时会抛出异常。

解决方案:

使用线程锁,对同一个事务操作,仅允许一个线程执行

示例说明

1.出现异常的代码

事务操作定义

using (var tran = new TransactionScope()){    ModuleOperate _module = new ModuleOperate();    //1.修改模块名称    _module.UpdateFirstName("模块:" + name);    //2.修改菜单    this.UpdateFirstName("菜单:" + name);    //提交事务    tran.Complete();}
多线程调用定义

Action update1 = (number) =>{    while (true)    {        //将上线文实例放在本线程中创建        MenuOperate _menu = new MenuOperate();        _menu.UpdateName(Count.ToString());        Console.WriteLine("-------");        Console.WriteLine(_menu.GetName2());        Count++;        Thread.Sleep(1000 * Convert.ToInt32(number));    }};for (int i = 0; i < 3; i++){    Task.Factory.StartNew(update1, i + 1);}
2.解决方案代码一:使用lock锁定

//对于锁推荐使用静态私有静态变量private readonly static object _MyLock = new object();/// /// 事务, 多表修改/// /// /// 
public bool UpdateName(string name){ lock (_MyLock) { using (var tran = new TransactionScope()) { ModuleOperate _module = new ModuleOperate(); 1.修改模块名称 _module.UpdateFirstName("模块:" + name); 2.修改菜单 this.UpdateFirstName("菜单:" + name); 提交事务 tran.Complete(); } } return true;}
3.解决方案代码二:使用Monitor封装TransactionScope

使用代码:

using (var tran = new EFTransaction()){    //修改名称    name = ">>ModuleOperate:" + name;    UpdateFirstName(name);    //2.修改菜单    MenuOperate _menu = new MenuOperate();    _menu.UpdateFirstName(name);    //提交事务    tran.Commit();}
EFTransaction类定义:

/// /// 自定义事务处理,/// 此版本,数据库上下文会出现多个,所以事务使用 TransactionScope /// 使用排它锁,确保事务的单线程执行/// public class EFTransaction : IDisposable{    private readonly static object _MyLock = new object();    ///     /// 当前事务对象    ///     private TransactionScope tran = null;    public EFTransaction()    {        Monitor.Enter(_MyLock);//获取排它锁        this.tran = new TransactionScope();    }    ///     /// 提交    ///     public void Commit()    {        tran.Complete();    }    ///     /// 混滚操作,在Dispose(),中自动调用回滚    ///     public void Rollback()    {        //提前执行释放,回滚        if (tran != null)            tran.Dispose();    }    public void Dispose()    {        if (tran != null)            tran.Dispose();        Monitor.Exit(_MyLock);//释放排它锁    }}

使用验证代码:不同线程对于同一个事务操作多个事务实例,在当前程序中事务操作代码顺序同步执行,不会出现异常和数据异常。

Action update1 = (number) =>{    while (true)    {        //同一个线程使用多个事务        MenuOperate _menu = new MenuOperate();        ModuleOperate _module = new ModuleOperate();        事务操作一        _menu.UpdateName(Count.ToString());        Thread.Sleep(Count); //错开等待时间,测试多线程异步问题        //事务操作二        _module.UpdateName(Count.ToString());        Console.WriteLine("-------");        Console.WriteLine(_menu.GetName2());        Count++;        Thread.Sleep(1000 * Convert.ToInt32(number));    }};for (int i = 0; i < 3; i++){    Task.Factory.StartNew(update1, i + 1);}

更多:

你可能感兴趣的文章
【win7无法识别u盘的解决办法】
查看>>
【布谷鸟来客提醒V4.0 官方版】淘宝店铺监控软件
查看>>
【教你修复win7下IE8主页被篡改的方法】
查看>>
【维护和保养电脑主机需12点注意】
查看>>
【幸福小助手V3.1绿色版】生活提醒软件
查看>>
【C#如何判断字符串是否为空串】
查看>>
【Linux编译安装httpsqs】
查看>>
【用C#实现启动另一程序的方法】
查看>>
【Android读写文件方法汇总】
查看>>
网线接法大全(RJ45型网线插头)
查看>>
【WinXP自我修复故障功能详解】
查看>>
【23招实用技巧让XP运行更快捷更可靠】
查看>>
【Wn8中如何关闭或开启自动播放功能】
查看>>
【Win7上装双系统完美体验Windows8】
查看>>
【解决Win7缩略图预览功能无法使用问题】
查看>>
【关闭Win7系统自动安装驱动程序功能】
查看>>
【iPod转换精灵V10.2 官方最新版】强大的视频转换功能
查看>>
【Windows编程的25个知识点】
查看>>
【Windows8完美解决强制要求驱动签名】
查看>>
2020年Java面试题总结(一)
查看>>