#php #sql #laravel #mariadb
#php #sql #laravel #mariadb
Вопрос:
в приложении Laravel у меня есть код, который считывает и выполняет весь файл SQL следующим образом:
DB::unprepared(file_get_contents(__DIR__ . '/seeds.sql'));
Файл seeds.sql
содержит несколько инструкций SQL. Код работает должным образом и выполняет все инструкции в файле, однако, как только он обнаруживает ошибку (например, некоторую опечатку), он просто не выполнит остальную часть файла без создания какого-либо исключения.
Я заметил, что если я помещу каждый оператор в его собственный DB::unprepared()
вызов, он вызовет исключение, как и ожидалось, однако, как только это 2-й или более поздний оператор в одном DB::unprepared()
вызове, исключение не генерируется, а остальные операторы молча не выполняются.
Не могли бы вы порекомендовать способ, который гарантирует, что все операторы в файле SQL были выполнены, если код не вызвал исключения?
Спасибо!
Ответ №1:
Я столкнулся с той же проблемой, обнаруженной при тестировании новой функции. Я попробовал то же решение, вызывая каждый оператор отдельно. Если кто-то найдет, как заставить это работать, я буду признателен.
В итоге я создал метод, подобный такому:
/**
* Executes the given sql statements into the database in a transaction doing a
* rollback if there is any exception. Avoids a problem of unprepared method, when it
* has a wrong statement in the middle never raises an exception once the first
* statement ir right.
*
* @param array $statements Sql statements.
* @return bool @see hhttps://laravel.com/api/8.x/Illuminate/Database/Connection.html#method_unprepared
* @throws DuplicatedKeyDataException Trying to insert / update data with duplicated
* key fields.
*/
public static function executeUnpreparedStatements(array $statements)
{
$conn = static::getConnection();
$conn->beginTransaction();
try {
foreach ($statements as $sqlStatement) {
$conn->unprepared($sqlStatement);
}
} catch (Exception $err) {
$conn->rollback();
if ($err instanceof QueryException amp;amp; $err->errorInfo[1] === 1062) {
throw new DuplicatedKeyDataException();
}
throw $err;
}
$conn->commit();
}
Может быть, вы могли бы сделать что-то вроде загрузки файла в память (или чтения его построчно), а затем выполнить что-то подобное.