#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 вы хотите, чтобы они были сохранены.