我已经研究了两天的交易,也许在吸收了如此多的信息之后,我似乎遗漏了一些明显的东西。这里的目标是阻止同时请求。如果condition
为true,则插入数据,之后condition
将为false。同时请求都condition
将在插入数据之前进行检查,然后都将尝试插入数据。
public async Task<ActionResult> Foo(Guid ID)
{
Debug.WriteLine("entering transaction scope");
using (var transaction = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions() { IsolationLevel = IsolationLevel.Serializable },
TransactionScopeAsyncFlowOption.Enabled
))
{
Debug.WriteLine("entered transaction scope");
var context = new DbContext();
Debug.WriteLine("querying");
var foo = context.Foos.FirstOrDefault(/* condition */);
Debug.WriteLine("done querying");
context.Foos.Add(new Foo());
/* async work here */
Debug.WriteLine("saving");
context.SaveChanges();
Debug.WriteLine("saved");
Debug.WriteLine("exiting transaction scope");
transaction.Complete();
Debug.WriteLine("exited transaction scope");
return View();
}
}
这是使用Fiddler一次执行两个请求时的调试输出:
进入交易范围 输入交易范围 查询 完成查询 进入交易范围 输入交易范围 查询 完成查询 保存 保存 已保存 System.Data.dll中发生类型为'System.Data.SqlClient.SqlException'的第一次机会异常 退出交易范围 退出交易范围
这是我对代码应该如何工作的理解:
DbContext.Database.Connection.BeginTransaction
,在执行查询时会引发错误:
当分配给命令的连接处于暂挂本地事务中时,ExecuteReader要求该命令具有事务。
该命令的Transaction属性尚未初始化。
TransactionScope
通常,使用基于任务的异步时会引起问题。http://entityframework.codeplex.com/discussions/429215但是,.NET 4.5.1添加了其他构造函数来处理此问题。如何在可撤销的异步/等待中配置TransactionScope?所以很明显,它没有像我想要的那样工作。有可能实现我的目标TransactionScope
吗?还是我必须升级到EF 6?
序列化无法解决旧的“先插入后检查”的问题。两个可序列化的事务可以同时评估条件,得出必须插入的结论,然后两者都尝试仅插入一个失败和一个成功。这是因为所有读取在可序列化隔离下彼此兼容(实际上,它们在所有隔离级别下均兼容)。
如何解决这个问题有很多流派。一些建议使用MERGE。有人建议在检查查询中使用锁定提示来获取X或U锁定。我个人建议始终插入并优雅地恢复重复的键冲突。是另一种方法做的工作是使用显式应用程序锁。
EF或System.Transactions确实只会增加疑问。从根本上讲,这是一个后端SQL问题。至于如何在线程之间流动事务作用域的问题,请参阅Get TransactionScope以与async / await一起使用(显然,从阅读OP中您已经知道了这一点……我没有在第一次阅读中进行注册)。您将需要此代码来使您的异步代码在适当的上下文中使用,但是阻止/锁定仍然是基本的后端问题。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句