Possiedo un'applicazione basata su PHP/5.2 che utilizza transazioni in MySQL/5.1 in modo da poter eseguire il rollback di più inserti se si verifica una condizione di errore. Ho diverse funzioni riutilizzabili per inserire diversi tipi di elementi. Fin qui tutto bene.Transazioni di rollback con LOCK TABLES
Ora ho bisogno di utilizzare il blocco della tabella per alcuni degli inserti. Come suggerisce il manuale ufficiale, sto utilizzando SET autocommit=0
anziché START TRANSACTION
quindi LOCK TABLES
non emette un commit implicito. E, come documentato, sbloccando tavoli impegna implicitamente qualsiasi transazione attiva:
E qui sta il problema: se ho semplicemente evito UNLOCK TABLES
, accade che la seconda chiamata a LOCK TABLES
impegna modifiche in sospeso!
Sembra che l'unico modo sia eseguire tutto il necessario LOCK TABLES
in una singola istruzione. Questo è un incubo di Mainteinance.
Questo problema risolve il problema?
Ecco un piccolo script di test:
DROP TABLE IF EXISTS test;
CREATE TABLE test (
test_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
random_number INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (test_id)
)
COLLATE='utf8_spanish_ci'
ENGINE=InnoDB;
-- No table locking: everything's fine
START TRANSACTION;
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND()));
SELECT * FROM TEST ORDER BY test_id;
ROLLBACK;
SELECT * FROM TEST ORDER BY test_id;
-- Table locking: everything's fine if I avoid START TRANSACTION
SET autocommit=0;
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND()));
SELECT * FROM TEST ORDER BY test_id;
ROLLBACK;
SELECT * FROM TEST ORDER BY test_id;
SET autocommit=1;
-- Table locking: I cannot nest LOCK/UNLOCK blocks
SET autocommit=0;
LOCK TABLES test WRITE;
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND()));
SELECT * FROM TEST ORDER BY test_id;
ROLLBACK;
UNLOCK TABLES; -- Implicit commit
SELECT * FROM TEST ORDER BY test_id;
SET autocommit=1;
-- Table locking: I cannot chain LOCK calls ether
SET autocommit=0;
LOCK TABLES test WRITE;
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND()));
SELECT * FROM TEST ORDER BY test_id;
-- UNLOCK TABLES;
LOCK TABLES test WRITE; -- Implicit commit
INSERT INTO test (random_number) VALUES (ROUND(10000* RAND()));
SELECT * FROM TEST ORDER BY test_id;
-- UNLOCK TABLES;
ROLLBACK;
SELECT * FROM TEST ORDER BY test_id;
SET autocommit=1;
perché avete bisogno di blocco? Qual è il vero problema? –
Ho bisogno di un blocco per garantire che solo un processo sia in grado di utilizzare un numero di sequenza per l'anno corrente e che non rimangano interruzioni nella sequenza. Il vero problema è che MySQL impegna automaticamente i set di dati non convalidati quando si tenta di utilizzare una funzionalità che non è consapevole delle transazioni come il blocco delle tabelle, superando così l'intero punto dell'utilizzo delle transazioni. –
Non puoi usare SELECT .... FOR UPDATE; ? Funziona bene nelle transazioni, nessun problema. Usa un singolo record per la sequenza e aggiorna questo record ogni volta. –