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 |
...
Si può eseguire un aggiornamento della riga, invece? (Non così sicuro di mutazione tavoli ...) – Sebas
No, genera un errore nella creazione del grilletto. – ppaulojr
Per riferimento personale, qual è l'errore? – Sebas