Taki scenariusz: pewna ilość danych do wstawienia do tabeli, gdy osiągnie próg już się nie wstawia, zasymulowałem ten scenariusz, w przypadku wielowątkowego (np. asp.net) pojawiły się problemy współbieżne.Jak rozwiązać konflikt współbieżności w ado.net
Moje pytanie brzmi, jak rozwiązać od jednoczesnego problemu, nie użyć obudowy lock
void Main()
{
Enumerable.Range(0,20).ToList().ForEach(i=>{
MockMulit();
});
}
//Start a certain number of threads for concurrent simulation
void MockMulit()
{
int threadCount=100;
ClearData();//delete all data for test
var tasks=new List<Task>(threadCount);
Enumerable.Range(1,threadCount).ToList().ForEach(i=>{
var j=i;
tasks.Add(Task.Factory.StartNew(()=>T3(string.Format("Thread{0}-{1}",Thread.CurrentThread.ManagedThreadId,j))));
});
Task.WaitAll(tasks.ToArray());
CountData().Dump();//show that the result
}
metoda jeden - współbieżność bardzo poważny
void T1(string name)
{
using(var conn=GetOpendConn())
{
var count=conn.Query<int>(@"select count(*) from dbo.Down").Single();
if(count<20)
{
conn.Execute(@"insert into dbo.Down (UserName) values (@UserName)",new{UserName=name});
}
}
}
Sposób drugi - umieścić sql razem może zmniejszyć równoczesne, ale nadal istnieją:
void T2(string name)
{
using(var conn=GetOpendConn())
{
conn.Execute(@"
if((select count(*) from dbo.Down)<20)
begin
--WAITFOR DELAY '00:00:00.100';
insert into dbo.Down (UserName) values (@UserName)
end",new{UserName=name});
}
}
metoda trzy - z blokadą d estroy jednoczesnego, ale nie sądzę, że jest to najlepsze rozwiązanie
private static readonly object countLock=new object();
void T3(string name)
{
lock(countLock)
{
using(var conn=GetOpendConn())
{
var count=conn.Query<int>(@"select count(*) from dbo.Down").Single();
if(count<20)
conn.Execute(@"insert into dbo.Down (UserName) values (@UserName)",new{UserName=name});
}
}
}
inna metoda pomaga
//delete all data
void ClearData()
{
using(var conn=GetOpendConn())
{
conn.Execute(@"delete from dbo.Down");
}
}
//get count
int CountData()
{
using(var conn=GetOpendConn())
{
return conn.Query<int>(@"select count(*) from dbo.Down").Single();
}
}
//get the opened connection
DbConnection GetOpendConn()
{
var conn=new SqlConnection(@"Data Source=.;Integrated Security=SSPI;Initial Catalog=TestDemo;");
if(conn.State!=ConnectionState.Open)
conn.Open();
return conn;
}
Jaki rodzaj bazy danych używasz, że nie może obsłużyć wstawiania danych? – Jake1164
Scenariusz, który próbujesz chronić, jest bardzo niejasny. Czy możesz powtórnie zmienić to, co próbujesz zrobić? –
@MarcGravell Właściwie zaprojektowałem działanie "Spike Goods" na naszej stronie e-commerce. Na przykład, tylko 20 towarów może kupić, ponieważ asp.net jest wielowątkowy, 21 rekordów pojawia się w naszej bazie danych! :( – JeffZhnn