Mysql
 sql >> Database >  >> RDS >> Mysql

In che modo le tabelle innodb vengono bloccate quando viene elaborato il trigger ON INSERT?

Per quanto riguarda i problemi di concorrenza, hai un 'facile' modo per prevenire eventuali problemi di concorrenza nel 2° metodo, all'interno della transazione eseguire una selezione nella riga articoli (il For update ora è implicito). Qualsiasi inserimento simultaneo sullo stesso articolo non potrà ottenere questo stesso blocco e ti aspetterà.

Con i nuovi livelli di isolamento predefiniti, senza nemmeno utilizzare il livello di serializzazione nella transazione non vedresti alcun inserimento simultaneo nella tabella dei voti fino alla fine della transazione. Quindi il tuo SUM dovrebbe rimanere coerente o apparire coerente . Ma se una transazione simultanea inserisce un voto sullo stesso articolo e si impegna prima di te (e questa seconda non vede il tuo inserto), l'ultima transazione da impegnare sovrascriverà il contatore e perderai 1 voto. Quindi esegui un blocco riga sull'articolo utilizzando una selezione prima (e fai il tuo lavoro in una transazione, ovviamente). È facile da testare, aprire 2 sessioni interattive su MySQL e avviare le transazioni con BEGIN.

Se usi il trigger sei in una transazione per impostazione predefinita. Ma penso che dovresti eseguire anche la selezione sulla tabella degli articoli per creare un blocco di riga implicito per i trigger simultanei in esecuzione (più difficile da testare).

  • Non dimenticare i trigger di eliminazione.
  • Non dimenticare i trigger di aggiornamento.
  • Se non utilizzi i trigger e il codice stayin, fai attenzione che ogni query di inserimento/cancellazione/aggiornamento su voti dovrebbe eseguire un blocco riga sull'articolo corrispondente prima della transazione. Non è molto difficile dimenticarne uno.

Ultimo punto:effettuare transazioni più difficili, prima di iniziare la transazione utilizzare:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

In questo modo non hai bisogno di blocchi di riga sugli articoli, MySQL rileverà che si verifica una potenziale scrittura sulla stessa riga e bloccherà le altre transazioni fino al termine. Ma non utilizzare qualcosa che hai calcolato da una richiesta precedente . La query di aggiornamento attenderà un rilascio del blocco sugli articoli, quando il blocco verrà rilasciato dalla prima transazione COMMIT il calcolo della SUM dovrebbe essere fatto di nuovo per contare. Quindi la query di aggiornamento dovrebbe contenere il SUM oppure fai un'aggiunta.

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

E qui vedrai che MySQL è intelligente, viene rilevato un deadlock se 2 transazioni stanno cercando di farlo mentre l'inserimento è stato eseguito in un tempo simultaneo. Nei livelli di serializzazione non ho trovato un modo per ottenere un valore sbagliato 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;

Ma preparati a gestire l'interruzione della transazione che devi ripetere.