一、说明
在EF中如果使用多个上线文访问数据库,那么事务通常使用TransactionScope。
在多线程使用TransactionScope的时候会抛出异常:
分布式事务已完成。请将此会话登记到新事务或 NULL 事务中。
解决方案:
方案一,使用线程锁,确保事务执行代码,同一时间仅有一个线程执行
方案二、封装处理TransactionScope,同一个事务实例,只能被同一个线程使用,其他的使用者等待,代码如下:
/// <summary>
/// 自定义事务处理,
/// 此版本,数据库上下文会出现多个,所以事务使用 TransactionScope
/// 使用排它锁,确保事务的单线程执行
/// </summary>
public class EFTransaction : IDisposable
{
private readonly static object _MyLock = new object();
/// <summary>
/// 当前事务对象
/// </summary>
private TransactionScope tran = null;
public EFTransaction()
{
Monitor.Enter(_MyLock);//获取排它锁
this.tran = new TransactionScope();
}
/// <summary>
/// 提交
/// </summary>
public void Commit()
{
tran.Complete();
}
/// <summary>
/// 混滚操作,在Dispose(),中自动调用回滚
/// </summary>
public void Rollback()
{
//提前执行释放,回滚
if (tran != null)
tran.Dispose();
}
public void Dispose()
{
if (tran != null)
tran.Dispose();
Monitor.Exit(_MyLock);//释放排它锁
}
}
使用示例:
using (var tran = new EFTransaction())
{
//修改名称
name = ">>ModuleOperate:" + name;
UpdateFirstName(name);
//2.修改菜单
MenuOperate _menu = new MenuOperate();
_menu.UpdateFirstName(name);
//提交事务
tran.Commit();
}
关于本异常,更多参考:
参考一:
分布式事务已完成。请将此会话登记到新事务或NULL事务中。
错误原因:
将分布式事务处理协调器与SQLServer配合使用的编程模型需要应用程序显式登记到分布式事务或从中脱离出来。
解决方案:
应用程序登记到分布式事务中之后,应用程序必须显式地从分布式事务中脱离或登记到另一个分布式事务中。这样将从上一个登记的事务中隐式脱离。有关从分布式事务脱离或登记到其中的准确语法,请参见该应用程序的编程接口手册。
将分布式事务处理协调器与SQLServer配合使用的编程模型需要应用程序显式登记到分布式事务或从中脱离出来。
解决方案:
应用程序登记到分布式事务中之后,应用程序必须显式地从分布式事务中脱离或登记到另一个分布式事务中。这样将从上一个登记的事务中隐式脱离。有关从分布式事务脱离或登记到其中的准确语法,请参见该应用程序的编程接口手册。
http://www.cnblogs.com/chriskwok/archive/2012/05/12/2497203.html
更多相关文章:
EntiryFramework中事务操作(三)事务回滚数据模型和数据库不对应问题