sql >> Base de Datos >  >> RDS >> Mysql

¿Cómo se bloquean las tablas de innodb cuando se procesa el activador ON INSERT?

Sobre los problemas de concurrencia, tienes un 'fácil' forma de evitar cualquier problema de concurrencia en el segundo método, dentro de su transacción realice una selección en la línea de artículos (el For update ahora está implícito). Cualquier inserción simultánea en el mismo artículo no podrá obtener este mismo bloqueo y lo esperará.

Con los nuevos niveles de aislamiento predeterminados, sin siquiera usar el nivel de serialización en la transacción, no verá ninguna inserción simultánea en la tabla de votación hasta el final de su transacción. Por lo tanto, su SUM debe permanecer coherente o parecer coherente . Pero si una transacción concurrente inserta un voto en el mismo artículo y se confirma antes que tú (y esta segunda no ve tu inserción), la última transacción en confirmar sobrescribirá el contador y perderás 1 voto. Entonces realice un bloqueo de fila en el artículo usando una selección antes (y hacer su trabajo en una transacción, por supuesto). Es fácil de probar, abre 2 sesiones interactivas en MySQL e inicia transacciones con BEGIN.

Si usa el disparador, está en una transacción por defecto. Pero creo que también debería realizar la selección en la tabla de artículos para hacer un bloqueo de fila implícito para la ejecución de activadores simultáneos (más difícil de probar).

  • No olvide eliminar los activadores.
  • No olvides activar los activadores de actualización.
  • Si no utiliza activadores y permanece en el código, tenga cuidado de que cada consulta de inserción/eliminación/actualización de votos realice un bloqueo de fila en el artículo correspondiente antes de la transacción. No es muy difícil olvidar uno.

Último punto:realice transacciones más difíciles, antes de comenzar la transacción use:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

De esta manera, no necesita bloqueos de fila en los artículos, MySQL detectará que se produce una escritura potencial en la misma fila y bloqueará las demás transacciones hasta que finalice. Pero no use algo que haya calculado a partir de una solicitud anterior . La consulta de actualización estará esperando una liberación de bloqueo en los artículos, cuando el bloqueo sea liberado por la primera transacción COMMIT el cálculo de SUM se debe hacer de nuevo para contar. Entonces, la consulta de actualización debe contener SUM o hacer una adición.

update articles set nb_votes=(SELECT count(*) from vote) where id=2; 

Y aquí verá que MySQL es inteligente, se detecta un interbloqueo si 2 transacciones intentan hacer esto mientras la inserción se ha realizado en un tiempo concurrente. En los niveles de serialización no he encontrado la forma de obtener un valor incorrecto con :

   SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
   BEGIN;
       insert into vote (...
       update articles set nb_votes=(
         SELECT count(*) from vote where article_id=xx
       ) where id=XX;
    COMMIT;

Pero esté preparado para manejar la transacción de última hora que debe rehacer.