C# 实体框架事务
我有一个在两台服务器上重复运行的程序。 我需要选择和更新程序中的DB记录,因此我需要EF的表锁或事务,否则程序的每个副本都可以选择和修改相同的记录。当第一个副本进行DB更改时,另一个副本不应运行相同的代码段 我在EF中找到TransactionScope,但它工作不正常,因为在运行第一个副本时,我可以在SQLServerMGMStudio中对该表进行许多选择和更新 我有一个简短的代码段,请验证它:C# 实体框架事务,c#,database,entity-framework,C#,Database,Entity Framework,我有一个在两台服务器上重复运行的程序。 我需要选择和更新程序中的DB记录,因此我需要EF的表锁或事务,否则程序的每个副本都可以选择和修改相同的记录。当第一个副本进行DB更改时,另一个副本不应运行相同的代码段 我在EF中找到TransactionScope,但它工作不正常,因为在运行第一个副本时,我可以在SQLServerMGMStudio中对该表进行许多选择和更新 我有一个简短的代码段,请验证它: using (TransactionScope transaction = new Transac
using (TransactionScope transaction = new TransactionScope())
{
//select some records which aren't locked by the other copy of the program
//condition: Locked==null
recipientsList = (from c in context.Recipients
where
c.SentToPlatform == false && c.PopupID != null &&
c.Message.MessageStatus == 2 && c.Locked == null
select c).Take(piecePerMinute).ToList();
foreach (var recipient in recipientsList)
{
//i need make some changes on the record, prevent it from the other copy of program
//I need to change locked column to true
recipient.Locked = true;
recipient.LockBy = ipAddress;
Console.Write("I");
Thread.Sleep(1000);
}
//close transaction
try
{
context.SaveChanges();
transaction.Complete();
} catch (Exception ex )
{
}
}
您需要通过SQL手动锁定表。我找到了这个帖子,我想这就是你需要的。但这并不令人满意 编辑:
这归结为乐观并发。您需要一种方法来确保每个应用程序都知道其下面的数据何时发生了更改,然后创建一种处理策略。我强烈建议阅读以下内容: 如果它们有帮助的话: 希望这能有所帮助-如果您有什么具体的需要澄清的,请告诉我 快乐编码, 干杯 Chris。从技术上讲,您要求的是一个运行时间更长的事务,其隔离级别高于默认级别。没有足够的信息让我知道您是否希望RepeatableRead或Serializable来避免幻象插入 你可以通过这样做来完成你的要求:
var opt = new TransactionOptions();
opt.IsolationLevel = IsolationLevel.Serializable;
using (var scope = new TransactionScope(TransactionScopeOption.Required, opt) ){
//read table code
//write table code
//save context & complete scope
}
话虽如此,我高度怀疑这是你真正想要的。可序列化事务会使数据库的大部分被锁定。这是什么意思?以下是Microsoft对可序列化事务的描述:
SERIALIZABLE指定以下内容:
语句无法读取已修改但尚未由其他事务提交的数据。
在当前事务完成之前,其他事务不能修改当前事务读取的数据。
在当前事务完成之前,其他事务无法插入键值在当前事务中任何语句读取的键值范围内的新行。
范围锁放置在与事务中执行的每个语句的搜索条件相匹配的键值范围内。这将阻止其他事务更新或插入符合当前事务执行的任何语句的任何行
交易
由于并发性较低,因此仅在必要时使用此选项
正如@Bertie指出的,实体框架是围绕乐观并发模型构建的。使用乐观并发OC有很多原因,处理不可避免的冲突有很多模式。OC让你更高更有趣。使用serializalbe事务处理任何事情都会让你像布鲁斯·威利斯(Bruce Willis)在12只猴子身上一样,塞满了大量的胸腺嘧啶,直直地流着口水,满地都是你的软垫房间。你现在不想这样,是吗?但为什么?如果我在MGMStudio中编写一个事务而没有提交或回滚,并且在另一个选项卡中编写一个select,您将看到select运行了,但没有得到结果。如果停止事务,select将立即运行。如果使用调试器单步执行代码,则可以实现此行为。当您在}上时,在SQLServerManagementStudio中会有完全相同的行为。TransactionScope使用using收集所有信息,然后将其提交到事务中using块调用的Dispose函数中。这就是你无法编辑表格的地方。根据本文,默认级别是可序列化的:因此,该级别在他的场景中是可序列化的。不是开玩笑的……我太习惯于指定选项了,我忘记了默认级别-duh。默认级别是READ COMMITTED。但是我分析了我的代码,我认为它不能正常工作。如果我打开一个上下文,在其中的某个地方打开一个transactionScope,它就不工作了!但是为什么呢?每个示例代码都显示,我需要打开一个tranScope,在其中我可以打开EF上下文。我的想法正确与否?我们正在走交叉路口。EF的默认级别取决于提供程序-对于SQL Server,它是读取提交的,请参阅。但是,当使用事务作用域时,默认级别是可序列化的,除非它在环境事务中登记,在该事务中它继承了其隔离级别。所有三个答案都集中在同一件事上,但从你的评论来看,我们似乎没有达到你想要的。我认为你应该花一些宝贵的时间思考你的问题以及如何清楚地表达它。
using (var ts = new TransactionScope())
{
var db = new Db();
var asd = from x in db.MyTable
where x.Id == 1
select x;
db.SaveChanges(); // you still can fire selects in the studio
asd.First().Name = "test2"; // now a change is made but not written to the transaction
db.SaveChanges(); // after this call you can't fire selects in the management studio, the table is locked
var asd2 = from x in db.MyTable
where x.Id == 1
select x;
asd2.First().Name = "test3";
db.SaveChanges(); // the table still is locked
}
// now you can do selects again, the table is unlocked
var opt = new TransactionOptions();
opt.IsolationLevel = IsolationLevel.Serializable;
using (var scope = new TransactionScope(TransactionScopeOption.Required, opt) ){
//read table code
//write table code
//save context & complete scope
}