Случай 1:
BEGIN;
INSERT ..
INSERT ..
COMMIT;
Другие соединения не увидят вставленные строки до завершения фиксации.Таким образом, BEGIN...COMMIT
сделал две вставки "атомарными".
Если что-то не получается, вам все равно нужна попытка / отлов, чтобы справиться с этим.
Не используйте LOCK TABLES
на InnoDBтаблицы.
Не беспокойтесь autocommit
;BEGIN..COMMIT
переопределяет его.
Мои утверждения применимы (вероятно) ко всем фреймворкам.(За исключением того, что некоторые из них не имеют «try» и «catch».)
Случай 2 : заблокировать строку в ожидании ее возможного изменения:
BEGIN;
SELECT ... FROM t1 FOR UPDATE;
... work with the values SELECTed
UPDATE t1 ...;
COMMIT;
Это удерживает других от строк SELECTed
до тех пор, пока после COMMIT
.
Случай 3 : Иногда IODKU полезно делать две вещи в одном атомарном операторе:
INSERT ...
ON DUPLICATE KEY UPDATE ...
вместо
BEGIN;
SELECT ... FOR UPDATE;
if no row found
INSERT ...;
else
UPDATE ...;
COMMIT;
Класс 4 : Пример классического банковского обслуживания:
BEGIN;
UPDATE accounts SET balance = balance - 1000.00 WHERE id='me';
... What if crash occurs here? ...
UPDATE accounts SET balance = balance + 1000.00 WHERE id='you';
COMMIT;
Если система падает между двумя UPDATEs
,Первое обновление будет отменено.Это удерживает систему от потери отслеживания перевода.
Случай 5: Возможно, близко к тому, что хочет ОП.В основном это комбинация случаев 2 и 1.
BEGIN;
SELECT ... FROM t1 FOR UPDATE; -- see note below
... work with the values SELECTed
INSERT INTO t1 ...;
COMMIT;
Примечания к случаю 5: SELECT..FOR UPDATE
должен содержать все строки, которые вы не хотите видеть в другом соединении.Это приводит к задержке другого соединения до этого соединения COMMITs
.(Да, это похоже на LOCK TABLES t1 WRITE
.)
Случай 6: «Обработка», которая должна быть внутри BEGIN..COMMIT, займет слишком много времени.(Пример: типичная онлайн-корзина.)
Для этого требуется механизм блокировки вне транзакций InnoDB.Один из способов (полезен для корзины) - использовать строку в какой-то дополнительной таблице и попросить всех проверить ее.Другой способ (более практичный в рамках одного соединения) - использовать GET_LOCK('foo')
и его друзей.
Общие обсуждения
Все приведенные выше примеры блокируют только строку (s) участвует, а не вся таблица (ы).Это делает действие намного менее инвазивным и позволяет системе справляться с гораздо большей активностью.
Также читайте о MVCC.Это общая техника, используемая под прикрытием, чтобы одно соединение могло видеть значения таблиц в какой-то момент времени, , даже когда другие соединения изменяют таблицы (ы) .
«Предотвращение вставок». Если MVCC запустить SELECT
, это похоже на получение моментального снимка всего, на что вы смотрите.Вы не увидите INSERTs
до тех пор, пока не завершите транзакцию, в которой находится SELECT
. Вы также можете съесть свой торт и съесть его.Таким образом, кажется, что вставки были заблокированы, но вы получаете выигрыш в производительности от их параллельного выполнения.Магия.