[mysql] Атомная модификация таблицы: можно ли обойтись без lock tables

dimabel

Допустим, есть таблица (назовём её `table1` в которой одно из полей (пусть оно называется `t2_id`) должно соответствовать автоинкрементному полю (назовём его `id`) другой таблицы (`table2` либо быть равным NULL.
Значение по умолчанию для `table`.`t2_id` - NULL, именно с этим значением и создаются записи в первой таблице.
Задача состоит в том, чтобы добавить во вторую таблицу запись, которая будет соответствовать записи в первой таблице. Добавление должно быть атомным, т.е., нельзя допустить, чтобы во второй таблице остались лишние записи, либо чтобы в первой таблице были битые ссылки.
Решение, которое мне пришло в голову сначала следующее (пхп-код, $id - значение автоинкрементного поля `id` для первой таблицы):
ignore_user_abort(1);
mysql_query("LOCK TABLES `table1` WRITE, `table2` WRITE",$connection_id);
if($res=mysql_query("SELECT `t2_id` FROM `table1` WHERE `id`=".$id{
$ar = mysql_fetch_assoc($res);
if( $inserted = is_null($ar['t2_id']) ){
mysql_query("INSERT INTO `table2` (.....) VALUES (......)",$connection_id);
mysql_query("UPDATE `table1` SET `t2_id`=".mysql_insert_id($connection_id)." WHERE `id`="$id);
}
} else { $inserted = FALSE; }
mysql_query("UNLOCK TABLES");
ignore_user_abort(0);

Можно-ли сделать лучше? В частности - убрать блокировки.
Дело в том, что коде форума, который я модифицирую, не нашел ни единой блокировки таблиц.

Marinavo_0507

> Можно-ли сделать лучше?
Использовать транзакции.
> Дело в том, что коде форума, который я модифицирую,
> не нашел ни единой блокировки таблиц.
В этом форуме тоже раньше не было.

dimabel

Во-первых, для MyISAM таблиц нет транзакций вроде.
Во-вторых, это слишком медленно, на сколько я помню.

gopnik1994

тогда эмулируй транзакцию
сделай лог и вперед...

dimabel

ммм... Зачем всё так усложнять?
Что, если так сделать? Сначала записать в `t2_id` какое-то служебное значение, а потом поправить его, после создания записи в `table2` ?
Кстати, я так понял, что в этом форуме тоже используются блокировки для создания обсуждений?

gopnik1994

в этом форуме на все блокировки и целостность просто положили

katrin2201

а инфа по средней\максимальной загрузке форума пользователями где-нить есть? =)

Marinavo_0507

В этом форуме мы везде транзакции поставили.

ruler

А я думаю, что это иногда так медленно грузится. Можно в часы пик снимать транзакции?

Marinavo_0507

Да, запрещать флудить, транзакций не будет.

rosali

нельзя допустить, чтобы во второй таблице остались лишние записи, либо чтобы в первой таблице были битые ссылки
А объясни, зачем тебе нужна целостность в обоих направлениях?

RED-GREEN

>Атомная

dimabel

Чтобы небыло лишних записей и никто не жаловался, что его пост пропал.

dimabel

Имелись в виду однотипные операции которые не выполняются паралельно.

rosali

Ну вот и объясни мне, что плохого, если какое-то время будут лишние записи. Вообще я плохо понимаю в каком смысле они лишние.... а ты?

dimabel

Лишние - в смысле, их кто-то добавлял, а ссылок на них нигде не осталось.

bansek

Нормально все, так и делай.
Заботай только все про локи в доке на dev.mysql.com, особенно комментарии.
А то, что в твоем форуме этого нет - ну дык все-таки не денежные операции проводятся, вот народ и не парится.

rosali

Все таки хочется вернуться к вопросу чтобы хотя бы для себя все прояснить
У тебя из этих двух таблиц потом данные как-то вынимаются, правильно?
Есть такие варианты:
1) Данные вынимаются через left join. тогде можно смело без всяких блокировок делать insert сначала во вторую таблицу, потом в первую. left join не заметит "неатомарности".
2) ---||--- right join ---||--- сначала в первую таблицу, потом во вторую, ---||---
3) ---||--- inner join. Тогда вообще пофигу, пока запись не появится в обеих таблицах, её не будет в inner join-е.
4) ---||--- outer join. Ну вот я собственно в предыдущем посте и спрашивал, зачем там может понадобиться outer join?
5) Вообще без join-ов, делаются по очереди select сначала из одной таблицы, потом из другой. Тогда никакая "атомарность" insert-а тебе не поможет. Разве что лочить _обе_ таблицы перед этими двумя select-ами, а потом отпускать, но это пи**ец, а не решение, никакой нагрузки держать не будет.
Оставить комментарий
Имя или ник:
Комментарий: