У меня есть приложение с PHP/5.2, которое использует транзакции в MySQL/5.1, чтобы он мог откатить несколько вставок, если выполнено условие ошибки. У меня есть разные функции повторного использования для вставки различных типов элементов. Все идет нормально.Откат транзакций с LOCK TABLES
Теперь мне нужно использовать блокировку таблиц для некоторых вставок. Как предлагает официальное руководство, я использую SET autocommit=0
вместо START TRANSACTION
, поэтому LOCK TABLES
не выдаёт неявный фиксатор. И, как описано, разблокирование таблицы неявно совершает любые активные сделки:
И здесь кроется проблема: если я просто избежать UNLOCK TABLES
, случается так, что второй вызов LOCK TABLES
совершает ожидающие изменения!
Похоже, что единственный способ - выполнить все необходимое LOCK TABLES
в одном заявлении. Это главный кошмар.
Имеет ли этот вопрос разумное обходное решение?
Вот небольшой тестовый скрипт:
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;
Почему вы должны блокировки? Какая проблема? –
Мне нужна блокировка, чтобы гарантировать, что только один процесс может использовать порядковый номер для текущего года, и в последовательности не осталось пробелов. Реальная проблема заключается в том, что MySQL автоматически фиксирует неаудированные наборы данных, когда вы пытаетесь использовать функцию, которая не является транзакцией, например блокировка таблицы, тем самым обманывая всю точку использования транзакций. –
Вы не можете использовать SELECT .... FOR UPDATE; ? Работает нормально в транзакциях, без проблем. Используйте одну запись для последовательности и обновляйте эту запись каждый раз. –