Mysql MySQL устранение deadlock

stalxed

Новичок
@fixxxer, doctrine 2 не поддерживает это(insert ignore, insert update if exists).

Касаемо самого select for update - можно попробовать снизить уровень изоляции транзакции до READ COMMITTED, в этом случае вроде негде полочиться.
Ну тогда другая транзакция легко может вклинится между select и insert и вставить дубликат.
Я уже всё, что можно о транзакциях прочитал.

Пути решения, которые я понял:
1) INSERT IGNORE
2) Минимизация транзакции и повтор в случае deadlock.
3) Лочить всю таблицу целиком.
4) Создание таблицы семафоров.

Пока попробую пункт 2, если что перейду на 3.
 
Последнее редактирование:

Вурдалак

Продвинутый новичок
REPLACE по идее подойдёт (который, судя по ссылке @fixxxer, поддерживается в Doctrine), если ты не используешь AUTO_INCREMENT.

Но ведь по идее можно сделать raw query, не?
 

stalxed

Новичок
@fixxxer, эта функция удобна с точки зрения БД, она помогает избежать проблему этого топика.
Но это рассмотрение вопроса с точки зрения Базы Данных.
А если смотрим с точки зрения бизнес логики, какой код понятнее?
1)
PHP:
<?php
$order = new Order('new_order_name');
$orderRepository->addIfNotExists($order);
2)
PHP:
<?php
if (! $orderRepository->existsByName('new_order_name')) {
    $order = new Order('new_order_name');
    $orderRepository->add($order);
}
Вот цитата Эрика Эванса:
Искушение объединить ФАБРИКУ и ХРАНИЛИЩЕ появляется еще в одном случае - при желании реализовать функцию "поиска или создания".
При этом клиент описывает, какой объект ему нужен, и если поиск показывает, что такого объекта еще не существует, то он создается и предоставляется клиенту.
Подобных функций следует избегать. В лучшем случае ее наличие создает совсем небольшие удобства, но даже кажущаяся ее полезность исчезает вовсе,
если в программе делается различие между СУЩНОСТЯМИ и ОБЪЕКТАМИ ЗНАЧЕНИЯМИ. Если клиенту нужен ОБЪЕКТ-ЗНАЧЕНИЕ, он обращается к фабрике и получает новый.
Как правило, различие между новым и уже существующим объектами играет важную роль в предметной области, и если средства архитектурной среды позволяют сымитировать отсутствие такого различия, то на самом деле они только запутывают дело.
 

stalxed

Новичок
REPLACE по идее подойдёт (который, судя по ссылке @fixxxer, поддерживается в Doctrine), если ты не используешь AUTO_INCREMENT.

Но ведь по идее можно сделать raw query, не?
Можно, тогда в репозиторий придется вставить функцию addIfNotExists(), ну не красиво, но м.б. тоже выход, раз за месяц 10 дедлоков появилось...
 

MiksIr

miksir@home:~$
Я вот так и не понял задачу. Зачем эти пляски с блокировками?
 

fixxxer

К.О.
Партнер клуба
А если смотрим с точки зрения бизнес логики, какой код понятнее?
Либо делать некрасиво, либо делать raw query с INSERT IGNORE, либо обрабатывать дедлоки. Какие еще варианты-то?

Я бы, кстати, сделал raw query.
 

Вурдалак

Продвинутый новичок
@stalxed Так тебе обновлять существующую запись не нужно? Тогда просто на уровне контракта
PHP:
interface OrderRepository
{
    /**
     * @throws OrderAlreadyExists
     */
    public function add(Order $order);
}
 

Вурдалак

Продвинутый новичок
Я бы все-таки кинул исключение. Если тебе понадобится добавить событие OrderWasPlaced, то INSERT IGNORE будет мешать.
 

fixxxer

К.О.
Партнер клуба
Ну почему, можно проверять affected rows. Это проще, чем разгребать коды ошибок. Или доктрина это сама умеет?
 
Последнее редактирование:

stalxed

Новичок
Я бы все-таки кинул исключение. Если тебе понадобится добавить событие OrderWasPlaced, то INSERT IGNORE будет мешать.
Это вопрос интерфейса репозитория, может быть именно как в твоем примере выше и сделаю, хороший вариант.

Ну почему, можно проверять affected rows. Это проще, чем разгребать коды ошибок. Или доктрина это сама умеет?
Это уже вопрос реализации, завтра займусь ею :) Пока и сам не знаю, как реализуется, но вроде реально....

а кнопку "сделай мне хорошо" вам в Доктрине не надо? :) ORM нужен для простого CRUD, такие задачи всегда на SQL делаются
@grigori, у тебя странные суждения:
По твоему MySQL не должен нормально блокировать не существующую запись по ID.
По твоему ORM не должна иметь INSERT IGNORE.

По мне это всё не нормально, это баги и недоделки из-за которых нужно городить костыли.
 
Последнее редактирование:

fixxxer

К.О.
Партнер клуба
Ну у него crud и есть.

В принципе, onInsertConflict: "ignore"/"update" в маппере - почему бы и нет?
 

fixxxer

К.О.
Партнер клуба
Why not? :) По мне, это несущественная деталь реализации.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
по-моему в ORM реализуется только базовый SQL, а в диалектах всегда будет только частичная поддержка

в принципе, нет ничего тупее терминологического спора, каждый волен понимать как хочет,
CRUD я понимаю буквально - аббревиатура 4 атомарных действий, которые прямо мапятся на запросы к базе, и все, никакой синхронизации,
а у него многопоточность с контролем целостности
то есть для меня его задача - это совместное редактирование google docs, а не CRUD
 
Последнее редактирование:

fixxxer

К.О.
Партнер клуба
За простыми create/update/delete на уровне domain model может спокойно стоять много всякого разного на уровне инфраструктуры. Если у тебя не Active Record =)
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Хорошо, если уж занялись этой псевдоинтеллектуальной фигней - вопрос :)
Любое понятие определяет то, что им не является.
Можешь привести пример задачи, связанной с обработкой данных в базе, и не являющейся CRUD в твоей интерпретации?

Иначе понятие CRUD становится синонимом "обработки данных в СУБД", то есть не термином, а так как CRUD - это все-же самостоятельный термин, следовательно, дефиниция логически ошибочна.
 
Последнее редактирование:

fixxxer

К.О.
Партнер клуба
CRUD - это вообще такой недотермин, применимо к чему угодно и понимай как хочешь. Типа MVC :)
Я в данном случае под CRUD понимаю c точки зрения базы OLTP, с точки зрения приложения - персистенцию моделей.

Вообще у ТС неоднозначная ситуация. Запись в лог, по сути, не относится к персистенции, и ее лучше делать отдельно, по событию. С другой стороны, у него на этот лог завязана уникальность. Короче, странная схема. Я бы постарался отделить эти вещи.
 
Последнее редактирование:
Сверху