PDO::prepare + множественный запрос не работает с транзакцией

Placido

Наблюдаю
Пытаюсь разобраться с подготовленными выражениями + транзакциями в PDO. Возникли сложности.
Суть проблемы. Есть код

PHP:
$conn->dbh->beginTransaction();
$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$stmt = $conn->dbh->prepare(
'UPDATE `таблица 1` ... (корректный SQL) ...;
INSERT INTO `таблица 1` ... (корректный SQL) ...;';

$stmt->bindValue(...);

try 
{ 
    $stmt->execute();
    $conn->dbh->commit();
} 
catch (Exception $e) 
{
    $dbh->rollBack();
    echo $e->getMessage();
}
Ситуации:
1. Если SQL корректный, код не работает. Ошибок, исключений не возникает.
2. Если в части UPDATE SQL с ошибкой, то выбрасывается исключение, как и должно быть.
3. Если в части UPDATE SQL корректный, а в части INSERT - с ошибкой, то исключение не выбрасывается, ошибки не происходит, но и код не выполняется.
4. Если убрать транзакцию - все выполняется нормально.
5. Если каждое выражение подготавливать отдельно, то все работает нормально, исключения выбрасываются когда нужно, но код выглядит коряво - приходится делать одинаковый $stmt->bindValue(...) для каждого выражения (а у меня есть подготовленные запросы, где необходимо сделать три запроса подряд (UPDATE, DELETE, INSERT), связывая каждый из них с десятком одинаковых параметров). Например, так:

PHP:
$conn->dbh->beginTransaction();
$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$stmt_1 = $conn->dbh->prepare(
'UPDATE `таблица 1` ... (корректный SQL) ...;');

$stmt_1->bindValue(...);

$stmt_2 = $conn->dbh->prepare(
'INSERT INTO `таблица 1` ... (корректный SQL) ...;');

$stmt_2->bindValue(...);

try 
{ 
    $stmt_1->execute();
    $stmt_2->execute();
    $conn->dbh->commit();
} 
catch (Exception $e) 
{
    $dbh->rollBack();
    echo $e->getMessage();
}
В чем может быть проблема, что использовать множественные запросы в одном prepare() вместе с транзакцией не получается, хотя без использования транзакций все происходит нормально?

Вопрос с подробным кодом можно найти на stackoverflow (задавал вопрос там, но пока вразумительного объяснения не получил).
 

Redjik

Джедай-мастер
Прежде чем просматривать и вникать в суть вопроса, ответь пожалуйста - таблицы в InnoDb ?
 

Placido

Наблюдаю
InnoDB стоит по умолчанию, но на всякий случай сейчас проверил на предмет глюков. Да, тип хранилища - InnoDB. Транзакции работают, если каждый запрос подготавливать отдельно, как я писал в п.5, но не работают, если подготавливать два запроса сразу. Если же транзакции не использовать, то два запроса сразу подготавливаются и try-catch работает.
 

Redjik

Джедай-мастер
По первому не подскажу, но у меня ощущение, что там нет транзакции, а по второму можно как то в цикл это тебе закинуть и try делать только на commit(), причем делать все через 1 stmt, а не делать их 10 штук (stmt_1, stmt_2)
 

Placido

Наблюдаю
По первому пункту смотрел в логе MySQL:
PHP:
33 Query	START TRANSACTION
33 Query	UPDATE ...;
                                
            INSERT ...
33 Quit
Если же сделать, как я писал в пятом пункте, то в логе есть и START TRANSACTION и COMMIT:
PHP:
34 Query	START TRANSACTION
34 Query	UPDATE ...
34 Query	INSERT ...
34 Query	COMMIT
34 Quit
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
1. надо по одному запросу на prepare/exec, много запросов одной командой - это асинхронные запросы, multi_query в mysql, а в PDO прямой поддержки нет.
да, с mysqlnd так тоже можно, но это скорее хак, и если вдруг на хостинге не mysqlnd - работать не будет
2. pdo-mysql не создает подготовленные выражения в базе, он их эмулирует т.к. настоящие подготовленные выражения в mysql работают медленнее.
как следствие, отправка текста запроса в базу и проверка его идет только на execute, а prepare молча скушает мусор
3. при желании эмуляцию можно отключить


в общем, загугли про эмуляцию prepared statements для mysql в pdo
 

Placido

Наблюдаю
Спасибо! Читаю об эмуляции. Как я понял, MySQL не поддерживает множественные запросы в prepare. Просто интересно, почему не возникает ошибки, когда с помощью PHP:: prepare() я пытаюсь выполнить сразу несколько запросов.
 

itprog

Cruftsman
2. pdo-mysql не создает подготовленные выражения в базе, он их эмулирует т.к. настоящие подготовленные выражения в mysql работают медленнее.
откуда информация?

PDO_MYSQL will take advantage of native prepared statement support present in MySQL 4.1 and higher. If you're using an older version of the mysql client libraries, PDO will emulate them for you.
ссылка
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Placido какое из слов в п.2 моего предыдущего поста тебе непонятно?
вот по сути вопроса http://rmcreative.ru/blog/post/neskolko-sql-zaprosov-za-odin-raz-cherez-pdo

itprog где 1й раз увидел - не помню, я просто всегда выставляю параметр http://www.yiiframework.com/doc/api/1.1/CDbConnection#emulatePrepare-detail
хорошо бы прокомментировать ман, щас сделаю
 

Placido

Наблюдаю
Placido какое из слов в п.2 моего предыдущего поста тебе непонятно?
вот по сути вопроса http://rmcreative.ru/blog/post/neskolko-sql-zaprosov-za-odin-raz-cherez-pdo
Мне не понятно, почему prepare("Несколько корректных запросов") + execute() без транзакции работает, а точно такой же prepare() + execute(), но с транзакцией, - нет.
 
Сверху