我有一个多线程环境,每个线程都想要在表中选择一行(如果不存在,则将其插入)并在其中增加一些内容。
基本上,每个线程都执行以下操作:
using (var context = new Entity.DBContext()) {
if(!context.MyTable.Any(...)) {
var obj = new MyTable() {
SomeValue = 0
};
context.MyTable.Add(obj)
}
var row = context.MyTable.SingleOrDefault(...);
row.SomeValue += 1;
context.SaveChanges();
}
示例中的问题:特定行的SomeValue =0。两个线程同时选择该特定行,它们都看到0。->它们都将其递增一次,而SomeValue的最终结果将为1,但是我们希望它是2。
我假设紧随另一个线程到达的线程应该等待(使用锁?)使第一个线程结束。但是我不能使其正常工作。
谢谢。
假设使用SQL Server,您可以执行以下操作:
create table T1 (
Key1 int not null,
Key2 int not null,
Cnt int not null
)
go
create procedure P1
@Key1 int,
@Key2 int
as
merge into T1 WITH (HOLDLOCK) t
using (select @Key1 k1,@Key2 k2) s
on
t.Key1 = s.k1 and
t.Key2 = s.k2
when matched then update set Cnt = Cnt + 1
when not matched then insert (Key1,Key2,Cnt) values (s.k1,s.k2,0)
output inserted.Key1,inserted.Key2,inserted.Cnt;
go
exec P1 1,5
go
exec P1 1,5
go
exec P1 1,3
go
exec P1 1,5
go
(请注意,它不一定是一个过程,我只是从一个线程中调用它以显示其工作原理)
结果:
Key1 Key2 Cnt
----------- ----------- -----------
1 5 0
Key1 Key2 Cnt
----------- ----------- -----------
1 5 1
Key1 Key2 Cnt
----------- ----------- -----------
1 3 0
Key1 Key2 Cnt
----------- ----------- -----------
1 5 2
即使有多个线程对此进行调用,我相信它也应该对访问进行序列化。我产生的输出只是为了表明每个调用者也可以知道他们将计数器设置为哪个值(在此为column Cnt
),即使之后另一个调用者立即更改了该值。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句