Laravel по-русски

Русское сообщество разработки на PHP-фреймворке Laravel.

Ты не вошёл. Вход тут.

#1 02.06.2017 10:40:15

Engineer
Откуда: Эстония
Сообщений: 4

Использование транзакций с моделями Eloquent

Laravel: 5.4.24
MySQL: 5.7.17 (InnoDB)

Привет всем! Посмотрел описание работы с транзакциями в документации Laravel. Там подробно расписано как действовать, взаимодействуя с БД через фасад DB, но примеров использования транзакций с  Eloquent ORM там не нашел. Указано только, что с ним тоже можно работать, используя инструменты DB фасада.
Попробывал набросать код, следуя интуиции:

    /**
     * Create a new user instance after a valid registration.
     *
     * @param  array  $data
     * @return User
     */
    protected function create(array $data)
    {
        $user = null;
        try{

            DB::beginTransaction();

            // Create a user record
            $user = User::create([
                'name' => $data['reg_fname'].' '.$data['reg_lname'],
                'email' => $data['reg_email'],
                'password' => bcrypt($data['reg_password']),
            ]);

            // Add a profile to the user
            $user->profile()->save(new UserProfile([
                'fname' => $data['reg_fname'],
                'lname' => $data['reg_lname']
            ]));

            DB::commit();

        } catch(\Exception $exception){

            DB::rollBack();

            // Allow Laravel engine to handle this exception
            throw $exception;
        }

        return $user;
    }

Тут создается сначала запись в таблице users, а затем добавляется запись в таблицу user_profiles. Все происходит внутри одной транзакции.

Проверил, вроде все работает как надо. При ошибке добавления записи в user_profiles, отменяется запись в таблицу users.

Вопросы: всё ли я делаю правильно? Можно ли и дальше в проекте использовать такой подход? Нет ли каких подводных камней?

Прошу, наведите на путь истинный, ибо не ведаю что творю, добро или зло. Не хотелось бы, чтобы в конце проекта настигла кара небесная smile

Не в сети

#2 02.06.2017 14:41:35

Re: Использование транзакций с моделями Eloquent

можно лучше

\DB::transaction(function () { … });

– при этом транзакция автоматически отменяется если внутри в коде будет выброшен любой эксепшен. более того – бросание эксепшена является стандартным средством отмены транзакции. если код выполнился без ошибок – транзакция будет закоммичена. снаружи полагается завернуть это добро в try … catch и обрабатывать ошибки

ещё если тебе нужны блокировки на отдельных записях (например – изменение баланса пользователя при покупке) обрати внимание на row-based locks в innodb. на элоквенте (и вообще на всех запросах построителя) это делается добавлением ->forUpdate. соответствует синтаксису SELECT … FOR UPDATE (есть в mysql и во всех других коннекторах ларавеля кроме sqlite). блокировка работает только внутри транзакции и автоматически снимается когда транзакция коммитится или откатывается

ещё в ларавеле можно открывать транзакцию внутри транзакции – базы такое конечно не все поддерживают (mysql – точно нет), поэтому ларавель использует внутренний счётчик чтобы отслеживать количество beginTransaction – когда последняя транзакция закрывается, тогда выполняется коммит. это даёт возможность внутри \DB::transaction() вызывать любой другой код, который тоже может использовать транзакции в своей работе.

Не в сети

#3 02.06.2017 15:44:22

Engineer
Откуда: Эстония
Сообщений: 4

Re: Использование транзакций с моделями Eloquent

Спасибо за развернутый ответ! Полезная информация, добавил в закладки.

Не в сети

Подвал раздела