DB::unrepared() не вызывает исключения при выполнении 2-й или более поздней инструкции

#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();
    }

  

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