Добавление новых записей в 2 таблицы

SQL во всех проявлениях - от ANSI-92 до TSQL.

Модераторы: Yurich, Absurd

Yurich
Сообщения: 107
Зарегистрирован: 23 фев 2004, 19:07

Duncon писал(а):В даном случае даже без блокировки внесёться конкретное значение исходя из очереди кто первый, провторов быть не может - смысл в транзакции нулевой...
Не вижу смысла комментировать этот [sarcasm] пост [/sarcasm]. Учите мат.часть...
Laba
Сообщения: 35
Зарегистрирован: 24 мар 2009, 17:47

natariga писал(а):понятно. спасибо!
я подумаю, как лучше.
Склоняюсь, к генерированию номера заказа, и запись его как поля в обе таблицы, а не auto_increment ID.

или все же values (LAST_INSERTED_ID(), 567, 2)..... :confused:

а не посоветуете, в каком из способов больше плюсов, а в каком минусов. :rolleyes:
В твоём случае auto_increment лучше. Есть его альтернатива

select max( id_order)+1 into :x from order;
insert into order (id_order,...) values( :x, ...);
insert into order_item( ..., id_order, ...) value( ..., :x, ...)
...

В случае с last_inserted и max()+1 транзакцию объявлять обязательно (правила хорошего тона)

Идеальный случай когда id_order будет вводится юзером. :D
Yurich
Сообщения: 107
Зарегистрирован: 23 фев 2004, 19:07

Хвост ветки не относящийся к теме обсуждения был перенесен в форум "Флейм".
natariga
Сообщения: 4
Зарегистрирован: 25 авг 2009, 09:24

Сейчас поняла, что все гораздо интереснее!
Ладно заказы, там вариант генерирования номера, а потом внесение этого поля в обе таблицы нормален.

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

Я почитала про транзакции и выполнение их в php.

Это надо использовать тогда еще и команды SET AUTOCOMMIT=0; и SET AUTOCOMMIT=0; ?

Ок, попробую такой вариант. Не зря же такие средства предусмотрены. Если нет выйдет, будем изобретать велосипед.
Аватара пользователя
Игорь Акопян
Сообщения: 1440
Зарегистрирован: 13 окт 2004, 17:11
Откуда: СПБ
Контактная информация:

смысл в транзакции есть всегда, когда нужно обеспечить атомарность изменения
Изображение
Yurich
Сообщения: 107
Зарегистрирован: 23 фев 2004, 19:07

natariga писал(а): Это надо использовать тогда еще и команды SET AUTOCOMMIT=0; и SET AUTOCOMMIT=0; ?
SET AUTOCOMMIT=0; выключает режим AUTOCOMMIT, в котором каждый отдельный запрос рассматривается как отдельная транзакция. Поэтому если ты хочешь использовать транзакции, состоящие из нескольких запросов, то надо выполнить SET AUTOCOMMIT=0; перед этим.
Аватара пользователя
Duncon
Сообщения: 2085
Зарегистрирован: 10 окт 2004, 14:11
Откуда: Питер
Контактная информация:

Не буду переубеждать в глупости для данного случая, гении мысли.. auto_increment в 1 таблицу 2 таблица ведомая ей auto_increment не нужен id обычное поле. Внесли в 1 проверили внесенее без LAST_INSERTED_ID внесли во 2, всё.. (И даже если следом выполнить LAST_INSERTED_ID команда пройдёт следом, время примерно 0.000х и меньше, нужна ацкая нагрузка чтоб начались пролёты мимо..)


Автор сделай всё 1 запросом, зачем список покупок хранить в отдельной таблице?


Yurich в игнор уходит, за мат часть.. Хам.
[syntax=Delphi] [/syntax]
Yurich
Сообщения: 107
Зарегистрирован: 23 фев 2004, 19:07

Duncon писал(а):Внесли в 1 проверили внесенее без LAST_INSERTED_ID внесли во 2, всё.. (И даже если следом выполнить LAST_INSERTED_ID команда пройдёт следом, время примерно 0.000х и меньше, нужна ацкая нагрузка чтоб начались пролёты мимо..)
LAST_INSERTED_ID() гарантирует получение последнего вставленного значения поля AUTO_INCREMENT именно в этой коннекции, так что даже если сервер очень нагружен "пролетов" не будет.
Duncon писал(а): Автор сделай всё 1 запросом, зачем список покупок хранить в отдельной таблице?
Просто автор следует правилам нормализации структуры БД и правильно делает. Я бы проигнорировал данный совет.
Duncon писал(а): Yurich в игнор уходит, за мат часть.. Хам.
Duncon, не зарывайся... Иди лучше сюда.
Laba
Сообщения: 35
Зарегистрирован: 24 мар 2009, 17:47

Duncon писал(а):Не буду переубеждать в глупости для данного случая, гении мысли.. auto_increment в 1 таблицу 2 таблица ведомая ей auto_increment не нужен id обычное поле. Внесли в 1 проверили внесенее без LAST_INSERTED_ID внесли во 2, всё.. (И даже если следом выполнить LAST_INSERTED_ID команда пройдёт следом, время примерно 0.000х и меньше, нужна ацкая нагрузка чтоб начались пролёты мимо..)
Этот вариант скорее всего ТС вполне подойдёт. Но может и нет.

И прежде чем рассуждать нужна транзакция в данном случае или нет, то нужно знать для чего они вообще нужны.

Позволю быть многословным.

1) самое очевидное, чтобы обеспечить физическую запись данных. Проще говоря, чтобы команда insert прошла и никому не помешала :) .

2) чтобы после внесения изменений можно было бы вернуться в исходное состояние. Порой откатить транзакцию нужно не только когда произошла ошибка, но и при успешном завершении.

3) чтобы обеспечить целостность данных. Типовой случай связка мастер-детайл.

4) чтобы была возможность подумать над "А вообще нужно ли вносить _такие_ изменения в таблицы?" :)

Всё это очень доступно описано вот в этом учебном курсе для начинающих ораклоидов. Щелкайте здесь -

Основы работы с базой данных Oracle

Подписывайтесь и читайте, ДУМАЙТЕ, примеряйте к своей практике. Очень полезно даже не для ораклоидов. Кстати, там и про первичные ключи расписано доходчиво.

Возвращаясь к случаю ТС, решение без транзакции будет хорошо работать если нет проблем с целостностью данных в связке мастер-детайл (см п.3).

И дело даже не в том, что связь есть по id_order. Это не та связь, которой надо остерегаться. Ведь нам ничто не мешает вставить запись в order, получить order_id, запомнить его где-то в недрах клиентского кода, ПОДУМАТЬ ЧАСИКА ДВА и добавить запись в order_item.

Дело в других зависимостях. Например, если бы в order хранилась сумма всех записей из order_item для id_order, то тогда всё было бы совершенно по другому. Нужно обязательно использовать транзакцию. Для успешной записи нужно гарантировать изменения сразу в двух таблицах. Скорее всего, этого у ТС нет.

И ещё один ньюанс в этом случае. Если ТС решит использовать автоинкрементную колонку и значение будет получать LAST_INSERTED_ID, то по хорошему транзакцию надо использовать (см п.1) Между вызовом insert и LAST_INSERTED_ID всё таки проходит время. Не час и даже не секунда. Но вызываются они из клиентского кода и никто не будет гарантировать, что он выполняется "без тормозов". Конечно, на это можно забить. Хотя...

...практика написания хорошего (читабельного, надежного и сопровождаемого) кода заключается в оформлении _всех_ изменений в формате _явных_ транзакций с _обязательной_ проверкой кода завершения _всех_ sql-команд (даже ROLLBACK, не говоря уже про COMMIT). В коде проверки у вас почти всегда есть возможность выполнить п.2 :)

А явное оформление транзакций позволяет сопровождающему программисту спустя годы выполнить п.4 :D
Ответить