En una tabla donde cada fila tiene un contador (solo un valor entero), necesito obtener el valor actual y aumentarlo al mismo tiempo .
Efectivamente, quiero hacer esto:
SELECT counter FROM table WHERE id=123
UPDATE table SET counter=counter+1 WHERE id=123
Pero hacer esto como dos consultas obviamente no es seguro para subprocesos: múltiples procesos que hacen lo mismo (en la misma fila) pueden obtener el mismo valor de contador. Necesito que todos sean únicos, por lo que cada proceso obtendría el valor actual real y lo aumentaría en uno.
Puedo pensar en una construcción donde implemente un bloqueo manual por fila, pero me pregunto si hay una manera más fácil de hacerlo.
Respuestas:
¡Las declaraciones de actualización funcionan perfectamente bien sin la selección anterior! Dado que las declaraciones individuales son seguras por definición, incluso dos consultas de ACTUALIZACIÓN realizadas al mismo tiempo solo darán como resultado que la fila se incremente dos veces.
Si realmente desea seleccionar el valor para su script PHP, hacer algo con él y luego desea actualizar este valor de contador exacto, puede hacer lo siguiente:
Esto inicia una nueva transacción, luego selecciona las filas que desea actualizar y las bloquea exclusivamente. Luego puede actualizarlos de forma segura sin preocuparse de que otros clientes cambien su contenido o incluso de acceder a las filas bloqueadas. Finalmente necesitas comprometer tus cambios.
También debe leer algo sobre los niveles de aislamiento . Es probable que no desee un valor como
READ UNCOMMITTED
nivel de aislamiento. Todo lo demás debería estar bien para este caso de uso.fuente
UPDATE table SET counter = counter + 1
es suficientemente atómico? ¿Todavía necesita las declaraciones de transacción que lo rodean?FOR UPDATE
y las transacciones, el valor que seleccionó podría ser diferente al que se utilizó en la consulta de actualización. Mi combinación de consultas bloquea la fila tan pronto como se selecciona el valor y, por lo tanto, garantiza que este valor de contador exacto se utilizará en la consulta de actualización.