Posiadam aplikację opartą na PHP/5.2, która wykorzystuje transakcje w MySQL/5.1, więc może wycofać wiele wstawień, jeśli zostanie spełniony warunek błędu. Mam różne funkcje wielokrotnego użytku do wstawiania różnych typów przedmiotów. Jak na razie dobrze.Transakcje rollback z TABLAMAMI ZABLOKOWANIA
Teraz potrzebuję użyć blokady stołu dla niektórych wkładek. Jak sugeruje oficjalny podręcznik, używam SET autocommit=0
zamiast START TRANSACTION
, więc LOCK TABLES
nie wydaje niejawnego zatwierdzenia. I, co zostało udokumentowane, odblokowanie tabele domyślnie dopuszcza żadnej aktywnej transakcji:
I tu leży problem: jeśli po prostu uniknąć UNLOCK TABLES
zdarza się, że drugie wywołanie LOCK TABLES
zobowiązuje oczekujące zmiany!
Wydaje się, że jedynym sposobem jest wykonanie wszystkich niezbędnych LOCK TABLES
w jednym wyciągu. To koszmar wieczny.
Czy ten problem ma sensowne obejście tego problemu?
Oto mały skrypt testowy:
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;
dlaczego trzeba blokowania? Jaki jest prawdziwy problem? –
Potrzebuję blokady, aby upewnić się, że tylko jeden proces jest w stanie użyć numeru sekwencji na bieżący rok i nie pozostawia żadnych przerw w sekwencji. Prawdziwy problem polega na tym, że MySQL automatycznie zatwierdza niezatwierdzone zestawy danych, gdy próbujesz użyć funkcji, która nie jest świadoma transakcji, takiej jak blokowanie tabel, co powoduje, że cały punkt wykorzystania transakcji jest bity. –
Nie można użyć opcji WYBIERZ ... DO AKTUALIZACJI; ? Działa dobrze w ramach transakcji, bez problemu. Użyj pojedynczego rekordu dla sekwencji i aktualizuj ten rekord za każdym razem. –