Pull to refresh

Comments 9

Например, TicketService можно использовать следующую транзакцию ACID, чтобы гарантировать, что новый заказ не нарушит кредитный лимит клиента

Вот постоянно удивляет это желание создать себе проблему, дабы потом её мужественно преодолевать.

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

INSERT INTO tickets (user_id, price ...)
SELECT users.user_id, payment.cost, ...
FROM users 
CROSS JOIN (SELECT ?) AS payment (cost)
WHERE users.user_id = ?
  AND users.credit_limit >= payment.cost
  AND ...

Тут не надо ни организовывать транзакцию, ни думать об уровне изоляции... А если кредит превысить, вставится ноль записей, и это без проблем отлавливается из статуса выполнения запроса.

Сервер БД вообще-то оптимизирован на одновременную работу нескольких независимых соединений с одними и теми же данными. Просто не мешайте ему.

что будет, если соседнее соединение одновременно с этим изменит credit_limit?или 100 соединений будут проверять остаток кредитного лимита и успешно его пройдут? точно ничего блокировать не нужно?

что будет, если

Один запрос - это всегда транзакция. Так что ничего блокировать не требуется. Второй либо будет ждать, пока первый отпустит данные, и возьмёт уже изменённые, либо будет обнаружено изменение исходных данных (несоответствие исходному снапшоту), и второй свалится по ошибке.

Insert вне транзакции не будет работать, так что транзакция будет так или иначе

Да ну? а мужики-то не знают...

Куча народу выполняет INSERT-запросы, в принципе даже не организуя/начиная транзакцию - и почему-то у них у всех работает. Что мы все делаем не так?

Давайте зададим некие предусловия:
мы говорим о современных реляционных базах, скажем, Оракле, Постгресе и Мускуле (InnoDB).
То, что вы делаете db_connect.execute("INSERT INTO () VALUES ()") без ручного открытия транзакции, не означает, что ее нет - просто происходит автокоммит. Но он происходит. Коммит же фиксирует (закрывает) транзакцию.
Конечно, если углубляться в дебри, можно устроить настоящие дебаты, но если использовать определенные упрощения, то это именно так.

То, что вы делаете db_connect.execute("INSERT INTO () VALUES ()") без ручного открытия транзакции, не означает, что ее нет - просто происходит автокоммит. Но он происходит. Коммит же фиксирует (закрывает) транзакцию.

Это зависит от того, как именно работает ваш db_connect.execute. Да, то, что методы в дополнение к указанному запросу навернут ещё хренову гору дополнительных запросов, не новость. Но либо метод безусловно формирует явную транзакцию (кстати, при этом он должен либо явно НЕ поддерживать мультизапросы, либо опять же явно указывать в документации, что в мультизапросе запрещены транзакционные запросы), либо это настраивается параметрами метода или соединения. И третий вариант - метод никаких транзакций не формирует, при этом в составе мультизапроса либо в составе последовательных запросов в рамках одного соединения допускаются транзакционные запросы (начать, зафиксировать, откатить, включить/выключить автокоммит и т.п.).

Так что заявлять, что транзакция формируется всегда - немножко неправильно. Зависит от реализации и/или настроек.

мы говорим о современных реляционных базах, скажем, Оракле, Постгресе и Мускуле (InnoDB).

Например, в случае MySQL вы можете включить General log и в нём посмотреть абсолютно все запросы, которые были посланы клиентским кодом. Там сразу и будет видно, формируется ли описываемая вами транзакция или нет. Скорее всего, в других СУБД тоже имеется такая возможность. Или, скажем, такую возможность может предоставлять драйвер доступа к данным.

Ну если вы настаиваете, то вы можете вообще зайти клиентом мускуля в БД, и сделать INSERT INTO.
В логе у вас будет только INSERT INTO (ну и факт входа в аудите, если настроен), а транзакция при этом все равно будет, просто "под капотом". Только в этот раз - не драйвера, а самого движка СУБД.
Вы не можете (с InnoDB) сделать вставку без механизма транзакции, это краегоугольный камень ACID реализации.

Так я ж с этого и начал! Любой отдельный запрос - это транзакция. А потому реализованный в виде одного, отдельного, запроса алгоритм не требует внешней транзакции, явной или скрытой под капотом метода или коннектора.

Sign up to leave a comment.