Опрос: $db->insert() и ON DUPLICATE в вашем любимом квери билдере или ORM

WMix

герр M:)ller
Партнер клуба
MiksIr
почему странно? а если ты напишешь update bla bla where id=5 чем это менее опасно?
обьекты можно изменять и использовать в измененном виде, никто не просит вызывать команду save()
 

MiksIr

miksir@home:~$
Тем, что мы создали новый объект, а не изменили, что с точки зрения работы с базой подразумевает появление новой строчки.
По какой-то причине произошло пересечение первичного ключа нового объекта с записью в базе - в итоге мы перезаписали в базе запись находясь в полной уверенности, что создали новую. Вот это мне кажется опасно с точки зрения посадить трудно уловимый баг.
 

WMix

герр M:)ller
Партнер клуба
ORM сделает SELECT запрос на существование
и ты будешь действовать точно также. хочешь быть уверенным сначало запроси!
но подумав скажу еще проще, как часто ты пишешь insert into .... set id=5 тебе ли не всеравно каким будет id? или ты наверняка пишешь когда знаешь!
 

fixxxer

К.О.
Партнер клуба
"...весь этот горький катаклизм, который я здесь наблюдаю..." (с)

Вы со своими ОРМами совсем забыли, как работает СУБД.

Можно делать так:

вариант 1. insert on duplicate key update

вариант 2.
PHP:
begin;
$row = select .. from table where id=:id for update;
if ($row) {
   update...
} else {
   insert...
}
commit;
просто select и потом insert или update, очевидно, будет нормально работать только на вашей тестовой среде с отсутствующим concurrency.
 

WMix

герр M:)ller
Партнер клуба
а может сразу так :)
PHP:
try{
 //insert
}
catch(..){
// update
}
 

Sad Spirit

мизантроп (Старожил PHPClub)
Команда форума
а может сразу так :)
PHP:
try{
 //insert
}
catch(..){
// update
}
Ну, кстати, это наиболее правильное решение, потому что в варианте fixxxer'а между "select ... for update" и "insert" в параллельной транзакции могли вставить запись. и опаньки.
 

Вурдалак

Продвинутый новичок
Ну, кстати, это наиболее правильное решение, потому что в варианте fixxxer'а между "select ... for update" и "insert" в параллельной транзакции могли вставить запись. и опаньки.
А в его варианте между INSERT'ом и UPDATE'ом запись могли удалить.
 

Фанат

oncle terrible
Команда форума
в доктрине можно написать просто save() она сама разберется добавлять или обновлять.
А вот такой ещё вопрос, ко всем.
То есть, должно быть 100% покрытие моделями. Никогда не пишем голый SQL, любые операции с данными - только через AR.

Вопрос: Так в реальной жизни бывает?
 

флоппик

promotor fidei
Команда форума
Партнер клуба
Я бы сказал, у нас 98% кода — именно модели. Голый SQL у нас изредка висит на каком-нибудь хитром административном функционале для всяких массовых фич, типа какие-нибудь цифирки в статистике пересчитать принудительно, или текстовые поля для всякой SEO лабуды перегенерить. Но именно то, что на уровне сайт+админка — только модели.
 

Sad Spirit

мизантроп (Старожил PHPClub)
Команда форума
Сравнительно с одним sql запросом с on duplicate, это АДЪ! Вам не кажется? ;)
Дык, кто ж спорит-то, хотя и в свежих версиях можно сделать без процедуры, одним запросом с WITH. Но on duplicate --- это очередная ни с чем не совместимая фишка MySQL, а описанный в стандарте MERGE, который и MySQL не умеет, --- тоже адокЪ по синтаксису и сложности реализации.
 

Gas

может по одной?
Вопрос: Так в реальной жизни бывает?
у меня нет, всегда найдётся какой-то статистический запрос или запрос с кучей джойнов, подзапросов, что-то типа

Код:
SELECT t.*, b.title AS status, log.date_create, b.id as status_id
FROM (
    SELECT cb.title AS brand, cm.title AS model, c.year, c.mileage, c.price_uah, u.phone, c.date_create as car_date_create,
            (SELECT id FROM car_status_buy_log WHERE id_car=c.id ORDER BY date_create DESC LIMIT 1) AS id_status_log,
            (SELECT date_create FROM car_status_buy_log WHERE id_car=c.id AND id_status=1 ORDER BY date_create ASC LIMIT 1) AS log_start,
            (SELECT date_create FROM car_status_buy_log WHERE id_car=c.id AND (id_status=5 OR id_status=6) ORDER BY date_create DESC LIMIT 1) AS log_end
    FROM car AS c
    JOIN user AS u on u.id=c.id_user
    JOIN car_dealer AS d on d.id=c.id_dealer
    JOIN car_model AS cm ON cm.id=c.id_model
    JOIN car_brand AS cb ON cb.id=cm.id_brand
    WHERE d.code='visitor' AND c.id_status_buy!=0
    ORDER BY c.date_create DESC
) AS t
LEFT JOIN car_status_buy_log AS log ON log.id=t.id_status_log
LEFT JOIN car_status_buy AS b ON b.id=log.id_status
WHERE log.id IS NULL OR b.days_expire=0 OR
    (b.days_expire>0 AND DATE_SUB(NOW(), INTERVAL b.days_expire DAY) < log.date_create)
это конечно адъ, но php-код что по понятности не лучше выходит, что работает в разы медленее.
 

ksnk

прохожий
Дык, кто ж спорит-то ... on duplicate --- это очередная ни с чем не совместимая фишка MySQL
Изначально вопрос ставился - расскажите мне как оно записывается в разнокалиберных AR'ах. Если AR понимает, что от него желает юзер и сгенерит в этом случае для mysql инструкцию с onduplicate, а для постгресса с With - это будет правильный AR. а если пользоваться try-catch с циклами, то говорить о правильном AR'е уже не придется.
 

WMix

герр M:)ller
Партнер клуба
А в его варианте между INSERT'ом и UPDATE'ом запись могли удалить.
мне напоминает это историю про 2 армии на 2х горах которые хотят напасть одновременно на вражеский. успех зависит от одновременного нападания и генерал посылает гонца "передай что нападаем в 10 утра", (они не могут напасть пока не будут уверены что другой отряд получит приказ)
гонец прибегает в другой отряд и говорит о нападении, его отправляют назад чтоб он сказал что они готовы, (они не будут нападать пока не убедятся что первый отряд узнает что им извесно о нападении)
когда гонец вернулся в первый его отправляют назад чтоб он передал что они слышали что другой отряд готов
итд.
чтобы передать что они слышали что они слышали что те слышали что они нападают..

это безвыходная ситуация
 

fixxxer

К.О.
Партнер клуба
Абсолютно верно, поэтому ещё и в цикл обернуть надо, см. например в postgres'овой документации.
Ох... Да, без цикла так или иначе проблемы. :)

Дык, кто ж спорит-то, хотя и в свежих версиях можно сделать без процедуры, одним запросом с WITH.
Ага, я тут я пейсал не так давно на эту тему.

on duplicate --- это очередная ни с чем не совместимая фишка MySQL
with, собственно, на тех же правах. :)

То есть, должно быть 100% покрытие моделями.
Это само собой разумеется в люблм случае, независимо от того, какой способ генерации/написания запросов используется.

Я, собственно, даже за что-то типа $foo->where(..)->order(..)->find в контроллере убивать готов, не говоря уж о sql-е вне модели.

Никогда не пишем голый SQL, любые операции с данными - только через AR.
Говносайты и бложики - запросто. Что-то серьезное - у меня ну может две модели из ста уложились бы в ar.
 

Sad Spirit

мизантроп (Старожил PHPClub)
Команда форума
мне напоминает это историю про 2 армии на 2х горах которые хотят напасть одновременно на вражеский. успех зависит от одновременного нападания и генерал посылает гонца "передай что нападаем в 10 утра", (они не могут напасть пока не будут уверены что другой отряд получит приказ)
гонец прибегает в другой отряд и говорит о нападении, его отправляют назад чтоб он сказал что они готовы, (они не будут нападать пока не убедятся что первый отряд узнает что им извесно о нападении)
когда гонец вернулся в первый его отправляют назад чтоб он передал что они слышали что другой отряд готов
итд.
чтобы передать что они слышали что они слышали что те слышали что они нападают..

это безвыходная ситуация
Ваще-то выход был явно обозначен: либо мы обновляем существующую запись, либо вставляем новую, не получив при этом exception.

Вот кстати интересно, а insert ... on duplicate key update работает именно так, как называется? И что случится, если в параллельной транзакции запись удаляют?
 

Фанат

oncle terrible
Команда форума
Что-то серьезное - у меня ну может две модели из ста уложились бы в ar.
Я дико извиняюсь за неграмотную формулировку.

Имелось в виду "модель на 100% покрывается AR?"

Ведь вот здесь
в доктрине можно написать просто save() она сама разберется добавлять или обновлять.
подразумевалось, что "доктриновский АРа разберется..." ?
 
Сверху