Tal escenario: una cierta cantidad de datos para insertar en una tabla, cuando alcanza un umbral que ya no se inserta, simulé este escenario, en el caso de multiproceso (eg asp.net) aparecieron problemas concurrentes.Cómo resolver el conflicto de simultaneidad en ado.net
Mi pregunta es cómo resolver el problema concurrente, no utilice el caso 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
}
método de un solo - concurrencia muy grave
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});
}
}
}
el método dos - poner el SQL juntos puede reducir concurrente, pero todavía existe
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});
}
}
método tres - con bloqueo d destruirlos del concurrente, pero yo no creo que es una mejor solución
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});
}
}
}
otro método ayuda
//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;
}
¿Qué tipo de base de datos está utilizando que no puede manejar la inserción de datos? – Jake1164
El escenario al que intenta proteger no es muy claro. ¿Puedes quizás reformular lo que estás tratando de hacer? –
@MarcGravell En realidad, diseñé una actividad de aumento de mercancías para nuestro sitio web de comercio electrónico. Por ejemplo, solo se pueden comprar 20 productos, porque asp.net tiene múltiples hilos, ¡21 registros aparecen en nuestra base de datos! :( – JeffZhnn