gpt4 book ai didi

c# - Entity Framework 的多线程事务中止

转载 作者:太空宇宙 更新时间:2023-11-03 13:53:56 26 4
gpt4 key购买 nike

我对多线程事务和 Entity Framework 有疑问。我有一个线程,它在事务中运行,我希望在同一个事务中有更多的工作线程。下面的代码说明了情况(EF 上下文中有一个虚拟实体,该代码基本上生成 5 个线程,我想在每个线程中插入一些实体,并在主线程的末尾插入一些实体,我想继续使用 DB,但是将整个过程隔离在一个事务中):

using(var scope = new TransactionScope())
{
int cnt = 5;
ManualResetEvent[] evt = new ManualResetEvent[cnt];

for(int i = 0; i < cnt; i++)
{
var sink = new ManualResetEvent(false);
evt[i] = sink;

var tr = Transaction.Current.DependentClone(
DependentCloneOption.BlockCommitUntilComplete);

Action run = () =>
{
using (var scope2 = new TransactionScope(tr))
{
using (var mc = new ModelContainer())
{
mc.EntitySet.Add(new Entity()
{
MyProp = "test"
});
mc.SaveChanges();
}
}

sink.Set();
};

ThreadPool.QueueUserWorkItem(r => run());
}

ManualResetEvent.WaitAll(evt);

using (var mc = new ModelContainer())
{
Console.WriteLine(mc.EntitySet.Count());
}
Console.ReadKey();
}

问题是,在 mc.SaveChanges(); 上抛出了异常。内部异常是 TransactionException:“该操作对于事务状态无效。”似乎在某个时候,交易被中止了。我认为是在第一个线程调用 SaveChanges() 之后,但我不确定。知道为什么交易被中止吗?

最佳答案

我发现这里发生了什么问题。基于this article ,我发现不可能在一个事务中同时处理两个 MSSQL 服务器连接。我还发现我在以前的代码中没有正确处理依赖事务。我的工作插图代码如下:

    class Context
{
public ManualResetEvent sink;
public DependentTransaction transaction;
}

static object syncRoot = new object();

static void Main(string[] args)
{
using (var scope = new TransactionScope())
{
int cnt = 5;
ManualResetEvent[] evt = new ManualResetEvent[cnt];

for (int i = 0; i < cnt; i++)
{
var sink = new ManualResetEvent(false);
evt[i] = sink;

var context = new Context()
{
// clone transaction
transaction = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete),
sink = sink
};

ThreadPool.QueueUserWorkItem(new WaitCallback(Run), context);
}

// wait for all threads to finish
ManualResetEvent.WaitAll(evt);

using (var mc = new ModelContainer())
{
// check database content
Console.WriteLine(mc.EntitySet.Count());
}

// after test is done, the transaction is rolled back and the database state is untouched
Console.ReadKey();
}
}

static void Run(object state)
{
var context = state as Context;

// set ambient transaction
Transaction oldTran = Transaction.Current;
Transaction.Current = context.transaction;

using (var mc = new ModelContainer())
{
mc.EntitySet.Add(new Entity()
{
MyProp = "test"
});

// synchronize database access
lock (syncRoot)
{
mc.SaveChanges();
}
}

// release dependent transaction
context.transaction.Complete();
context.transaction.Dispose();

Transaction.Current = oldTran;

context.sink.Set();
}
}

这可能不是编写多线程业务层的好方法,但这种共享事务方法对我的测试非常有用。使这项工作唯一需要修改的是覆盖 Db 上下文并在测试运行中同步保存方法。

关于c# - Entity Framework 的多线程事务中止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12918421/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com