2013-06-07 22 views
8

Sto cercando di creare un trigger che genera e memorizzare un hash per l'indice auto_increment ma tutte le soluzioni che ho provato non ha funzionato:MySQL trigger per generare un hash per un indice auto_increment

DELIMITER // 
CREATE TRIGGER insertTable1 AFTER INSERT ON Table1 
FOR EACH ROW 
    BEGIN 
    SET NEW.hash = calc_hash_udf(NEW.id); 
    END // 
DELIMITER ;; 

E ' dice che non posso modificare una NEW dopo la INSERT, e prima che il INSERT non ho il valore auto_increment:

ERRORE 1442 (HY000): Impossibile aggiornare la tabella 'tabella 1' in funzione memorizzata/grilletto perché è già usato dall'istruzione che ha invocato questa funzione/trigger memorizzato.

+0

Si può eseguire un aggiornamento della riga, invece? (Non così sicuro di mutazione tavoli ...) – Sebas

+0

No, genera un errore nella creazione del grilletto. – ppaulojr

+0

Per riferimento personale, qual è l'errore? – Sebas

risposta

5

Non è possibile modificare il valore dopo il la riga è stata inserita. Pertanto, SET NEW.column è disponibile solo in un trigger BEFORE.

Inoltre non è possibile utilizzare un normale UPDATE sia because:

una funzione memorizzata o trigger non può modificare una tabella che è già in uso (per la lettura o la scrittura) dalla dichiarazione che ha invocato la funzione o grilletto.

Infine, in un trigger BEFORE INSERT, il valore AUTO_INCREMENT non è stato ancora generato, e NEW.id è 0.

Il trucco: in un trigger BEFORE, controllare manualmente la definizione della tabella per la prossima AUTO_INCREMENT valore:

ATTENZIONE: questo funziona solo con MyISAM, non con InnoDB

ho suppongo potrebbe funzionare con InnoDB se innodb_autoinc_lock_mode = 0 ma non sono in grado di dirlo con certezza.

DELIMITER //  

    CREATE TRIGGER insertTable1 BEFORE INSERT ON Table1 FOR EACH ROW 
    BEGIN 
     DECLARE next_ai INT; 
     SELECT auto_increment INTO next_ai 
      FROM information_schema.tables 
      WHERE table_schema=DATABASE() AND table_name = 'Table1'; 
     SET NEW.hash = calc_hash_udf(next_ai); 
    END // 

DELIMITER ; 

[modifica 1]

Per quanto riguarda la proprietà a prova di concomitante di questo approccio, posso dire:

  • con MyISAM, cui sono disponibili solo tavolo-serrature, il la sicurezza è ovvia: un blocco esclusivo sul/i tavolo/i è acquisito da qualsiasi INSERT/UPDATE/DELETE e non può verificarsi alcun accesso concorrente.

  • con InnoDB, questo è meno ovvio. Per il "traditional lock mode", il manuale dice:

InnoDB utilizza una serratura speciale denominata tabella a livello di blocco AUTO-INC per inserti in tabelle con colonne AUTO_INCREMENT. Questo blocco è normalmente tenuto alla fine della dichiarazione

Suppongo che questo sia sicuro in questo caso.

non ho familiarità con questi concetti, quindi non ho potuto dire di sicuro. Sembra davvero dubbio.

[modifica 2]

Ho eseguito il test di seguito con diverse impostazioni per innodb_autoinc_lock_mode:

CREATE TABLE t ( ai INT AUTO_INCREMENT PRIMARY KEY, trigval INT, bandiera BOOL );

Un trigger sul tavolo fa SET NEW.trigval = next_ai con il metodo di cui sopra.

In una transazione, un lungo inserto è realizzato da:

INSERT INTO t SELECT null, null, 0 FROM (SELECT * FROM a_very_big_table) AS tmp; 

In una seconda operazione, ho costantemente a rilasciare la seguente dichiarazione:

INSERT INTO t VALUES (null, null, 1); 

Alla fine, cerco discrepanze:

SELECT * FROM t WHERE ai <> trigval; 

Con innodb_autoinc_lock_mode = 0 ("tradizionale"), sembra di essere al sicuro. Qualsiasi tentativo simultaneo di inserimento nel tavolo è bloccato fino al completamento del lungo INSERT.

Tuttavia, non mi aspettavo che, con i modi 1 (il default) e 2, questo approccio è chiaramente sbagliato. information_schema.tables.auto_increment viene aggiornato dai passaggi. Questo è il risultato che ho ottenuto:

 
+-------+---------+------+ 
| ai | trigval | flag | 
+-------+---------+------+ 
|  3 |  4 | 0 | 
|  5 |  8 | 0 | 
|  9 |  16 | 0 | 
| 17 |  32 | 0 | 
| 33 |  64 | 0 | 
| 65 |  128 | 0 | 
... 

+0

Molto impressionante. Ha funzionato molto bene. – ppaulojr

+1

Solo una curiosità è sicura quando più fonti stanno creando inserti? – ppaulojr

+1

@ppaulojr Mi stavo ponendo la stessa domanda, e non ne sono sicuro. Per favore controlla la mia ultima modifica. Continuerò a cercare perché questo mi disturba. Rimanete sintonizzati. – RandomSeed

Problemi correlati