LINUX.ORG.RU

mysql и transactions


0

0

Есть таблица t1 типа
CREATE TABLE t1 (id INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (id));
в нее нужно добалять записи.

И есть таблица t2 типа(max_id
CREATE TABLE t2 (max_id INT);
которая содержит только одну запись - максимальный id в таблице t1.

Структуру таблиц и принцип работы менять нельзя.
Задача: написать запрос атомарно добаляющий одну запись в таблицу t1
и изменяющий запись в таблице t2. Что то типа того:

BEGIN;
INSERT INTO t1 (id) VALUES (null);
UPDATE t2 SET max_id=LAST_INSERT_ID();
COMMIT;

В случае если проходят две параллельных транзакции, первая выполнила begin/insert, тут полностью отработала вторая и первая выполнила update/commit, то таблица t2 будет содержать не максимальный id.

Вопрос как это можно побороть ?!!
С LOCK TABLES ничерта не получается, если до begin заблокировать таблицу t2, то такое впечатление что begin снимает блокировку...


PS: имел ввиду "если до begin заблокировать таблицу t1"...

Получается блокировать только в такой последовательности:

BEGIN;
LOCK TABLES t1 write, t2 write;
INSERT INTO t1 (id) VALUES (null);
UPDATE t2 SET max_id=LAST_INSERT_ID();
COMMIT;
UNLOCK TABLES;

Но это imho извращение какое-то :(

do
() автор топика
Ответ на: комментарий от fenring

Мне кажется оно тут не подойдет:

BEGIN;
SELECT * FROM t2 FOR UPDATE;
INSERT INTO t1 (id) VALUES (null);
UPDATE t2 SET max_id=LAST_INSERT_ID();
COMMIT;

Точно так же дает несогласованные данные при сценарии описанном выше :(

do
() автор топика
Ответ на: комментарий от fenring

> Хотя извини, фигню сморозил :)

Или нет... %))

BEGIN;

SELECT max_id FROM t2 FOR UPDATE;

INSERT INTO t1 (id) VALUES (null);

UPDATE t2 SET max_id=LAST_INSERT_ID();

COMMIT;

Так, интересно, работать будет? :)

fenring
()
Ответ на: комментарий от do

> Нет - я проверял. :(


Установил себе MySQL, посмотрел что к чему... :) Проблема в том, что MySQL по-умолчанию делает таблицы типа MyISAM, а они не поддерживают транзакций и row-level locking.

Лечить так:

CREATE TABLE t1 (id INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (id)) Type=InnoDB;

CREATE TABLE t2 (max_id INT) Type=InnoDB;

fenring
()
Ответ на: комментарий от fenring

Таблицы и так были innodb.
Если делать как было описано выше begin/insert в первой транзакции, полностью вторая транзакция и update/commit - получаем не максимальный id.

Я переделал дизайн уже - все это больше не нужно, но все равно было бы интересно узнать как такое лечить. Спасибо за ответ !

do
() автор топика

Мне в другом форуме предложили простое и очевидное решение:

UPDATE t2 SET max_id=LAST_INSERT_ID() WHERE max_id<LAST_INSERT_ID();

Так просто, а в голову не пришло :))) Вот что значит глаз замылился...

do
() автор топика
Ответ на: комментарий от fenring

Читайте доки. LOCK/UNLOCK TABLES неявно коммитит транзакцию. Поэтому хрен что так получится.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.