Tengo una pregunta sobre SQL y estrategias de bloqueo. Como ejemplo, supongamos que tengo un contador de vistas para las imágenes en mi sitio web. Si tengo un procedimiento almacenado o similares para realizar las siguientes declaraciones:Incremento atómico SQL y estrategias de bloqueo: ¿es esto seguro?
START TRANSACTION;
UPDATE images SET counter=counter+1 WHERE image_id=some_parameter;
COMMIT;
Supongamos que el contador para un image_id específica tiene un valor '0' en el tiempo t0. Si dos sesiones actualizan el mismo contador de imágenes, s1 y s2, comienzan al mismo tiempo en t0, ¿hay alguna posibilidad de que estas dos sesiones lean el valor '0', aumenten a '1' y ambas intenten actualizar el contador a '1 ', ¿entonces el contador obtendrá el valor' 1 'en lugar de' 2 '?
s1: begin
s1: begin
s1: read counter for image_id=15, get 0, store in temp1
s2: read counter for image_id=15, get 0, store in temp2
s1: write counter for image_id=15 to (temp1+1), which is 1
s2: write counter for image_id=15 to (temp2+1), which is also 1
s1: commit, ok
s2: commit, ok
Resultado final: valor incorrecto '1' para image_id = 15, debería haber sido 2.
Mis preguntas son:
- ¿Es este escenario posible?
- Si es así, ¿importa el nivel de aislamiento de transacción?
- ¿Hay una resolución de conflictos que detectaría un conflicto como un error?
- ¿Se puede usar alguna sintaxis especial para evitar un problema (algo así como Compare And Swap (CAS) o técnicas de bloqueo explícitas)?
Me interesa una respuesta general, pero si no hay ninguna, me interesan las respuestas específicas de MySql e InnoDB, ya que intento utilizar esta técnica para implementar secuencias en InnoDB.
EDITAR: El siguiente escenario también podría ser posible, dando como resultado el mismo comportamiento. Supongo que estamos en el nivel de aislamiento READ_COMMITED o superior, por lo que s2 obtiene el valor desde el inicio de la transacción, aunque s1 ya escribió '1' en el contador.
s1: begin
s1: begin
s1: read counter for image_id=15, get 0, store in temp1
s1: write counter for image_id=15 to (temp1+1), which is 1
s2: read counter for image_id=15, get 0 (since another tx), store in temp2
s2: write counter for image_id=15 to (temp2+1), which is also 1
s1: commit, ok
s2: commit, ok
mysql http://stackoverflow.com/questions/4358732/is-incrementing-a-field-in-mysql-atomic || MS http://stackoverflow.com/questions/193257/in-ms-sql-server-is-there-a-way-to-atomically-increment-a-column-being-used-a –