как исключить некоторый оператор блока из транзакции — Laravel 5.7

#laravel #eloquent

#laravel #красноречивый

Вопрос:

Мне нужно, чтобы некоторый оператор (который существует в блоке транзакции) выполнялся непосредственно в базе данных без транзакции, пример :

 DB::beginTransaction();

//query A : insert or update to some tables in transaction

//**I need some of the result of (query A) to be saved in Database without transaction**

//insert or update to some tables in transaction

DB::commit();
  

Комментарии:

1. Без некоторого фактического кода трудно представить общий случай, в котором внутри транзакции необходим нетранзакционный запрос. Не могли бы вы добавить больше деталей к своему вопросу, для меня это звучит как проблема XY.

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

3. @JoseHenriqueFelipetto Мне нужен некоторый результат строк, добавленных в транзакцию, и вставить его в базу данных без транзакции, независимо от того, была ли транзакция откатана или зафиксирована.

Ответ №1:

[РЕДАКТИРОВАТЬ] После повторного прочтения вашего вопроса кажется, что я, возможно, неправильно понял некоторые части. Если, сказав

Мне нужно, чтобы некоторые результаты (запроса A) были сохранены в базе данных без транзакции

Вы имеете в виду «использовать значения, вставленные в транзакцию до завершения транзакции», я думаю, это невозможно. Вы все еще можете использовать мой ответ для мгновенной вставки или обновления данных, но вы не сможете прочитать то, что вы вставили в транзакцию до завершения транзакции.


Вы можете дублировать соединение, которое вы используете для транзакции в database.php . Для этого примера давайте предположим, что вы вызываете это 'mysql_outside_transaction' . У вас должно быть что-то вроде этого в database.php файле после подключения по умолчанию:

 'mysql_outside_transaction' => [
            'driver' => 'mysql',
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'strict' => true,
            'engine' => null,
        ],
  

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

Опять же, для примера, если у вас есть экземпляр $modelA , вы можете указать ему использовать ваше второе соединение: $modelA->setConnection('mysql_outside_transaction'); . С этого момента каждая операция с базой данных, исходящая из этого экземпляра, будет выполняться вне вашей транзакции (поскольку при этом будет использоваться второе настроенное вами соединение, а не то, которое использовалось для транзакции).

Не забывайте, что вы можете настроить соединение для использования многими способами. Это может быть непосредственно в атрибутах класса модели ( protected $connection = 'your_connection'; ), с DB фасадом ( DB::connection('your_connection'); ) и, вероятно, другими способами, о которых я сейчас не думаю 🙂

Комментарии:

1. спасибо за ваш ответ, но почему я получаю эту ошибку при попытке обновить значение в другом соединении: SQLSTATE [HY000]: Общая ошибка: превышен тайм-аут ожидания блокировки 1205; попробуйте перезапустить транзакцию.

2. Трудно сказать без фактического фрагмента кода. Обновляете ли вы одну и ту же строку дважды, один раз с помощью транзакции, а другой раз с помощью нетранзакционного соединения (все это в рамках транзакции)? Транзакции могут усложняться, если вы выполняете запросы к связанным вещам (например, одновременно изменяете одну и ту же строку и тому подобное).

3. да, я дважды обновляю один и тот же raw в соответствии с вашим ответом (установите другое соединение, чтобы избежать транзакции)!

4. Хорошо, вот почему это не удается. Фактический случай, когда мне понадобилось что-то вроде вас, был, когда я пытался обновить статус импорта во время длительного импорта данных. Импорт данных был обработан транзакцией, поэтому я не смог напрямую обновить import модель, вот почему я нашел обходной путь, объясненный в моем ответе. Но в моем случае две таблицы напрямую не связаны. Насколько я знаю, то, что вы пытаетесь сделать, невозможно, поскольку строка, которую вы пытаетесь обновить, заблокирована при запуске транзакции. Я могу ошибаться, никто не знает всего, но я действительно сомневаюсь, что вы можете это сделать (по крайней мере, с MySQL) :/

5. Вы хотите сказать, что он должен вести себя как контрольная точка для queryA и queryB, но не для queryC? Например, вы хотите, чтобы при возникновении ошибок queryC выполнялся откат, но A и B вы хотите, чтобы они были сохранены.