本文共 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();}多线程调用定义
Action2.解决方案代码一:使用lock锁定
//对于锁推荐使用静态私有静态变量private readonly static object _MyLock = new object();///3.解决方案代码二:使用Monitor封装TransactionScope/// 事务, 多表修改/// /// ///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;}
使用代码:
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
更多: