Задать вопрос

Как сохранить 2 модели в транзакции Yii2?

Есть форма/модель. В функции происходит сохранение 2х моделей, User и Token.
Сохранение происходит. Но!!! Если не удается сохранить модель Token, записи в базу не добавляются, но при следующей успешной записи в модели User, id нового пользователя будет больше на прошлое количество неверных сохранений.
Допустим последний пользователь с id=10, было две неверных попытки сохранения, и затем прошло удачное сохранение, id =13.
Это нормально или у меня косяк кода?
<?php
namespace frontend\modules\account\models\forms;

use frontend\modules\account\models\Token;
use Yii;
use common\models\User;
use yii\base\Model;

class RegistrationForm extends Model
{
    public $nickname;
    public $email;
    public $password;

    /**
     * Validation rules
     * @inheritdoc
     * @return array
     */
    public function rules()
    {
        return [
            // nickname rules
            'nicknameTrim'     => ['nickname', 'trim'],

            // email rules
            'emailTrim'     => ['email', 'trim'],

            // password rules
            'passwordTrim' => ['password', 'trim'],
        ];
    }

    /**
     * Field name
     * @inheritdoc
     * @return array
     */
    public function attributeLabels()
    {
        return [
            'nickname' => 'Никейм',
            'email' => 'E-mail',
            'password' => 'Пароль',
        ];
    }

    /**
     * Form name
     * @inheritdoc
     * @return string
     */
    public function formName()
    {
        return 'registration-form';
    }
    
    /**
     * Registrations function
     * @return bool
     * @throws \Exception
     * @throws \Throwable
     */
    public function registration()
    {
        if ( !$this->validate() ) {
            return false;
        }

        $transaction = Yii::$app->db->beginTransaction();

        try {
            $user = new User();
            $user->nickname = $this->nickname;
            $user->email = $this->email;
            $user->generatePassword($this->password);
            $user->save();

            $token = new Token();
            $token->user_id = $user->getPrimaryKey();
            $token->save();

            $transaction->commit();

        } catch (\Exception $e) {
            $transaction->rollBack();
        }
        
        return true;
    }
}
  • Вопрос задан
  • 591 просмотр
Подписаться 2 Простой Комментировать
Решения вопроса 2
Decadal
@Decadal
Это нормально, потому что вставка использует число из последовательности автоинкремента.
Например, транзакция включает два запроса: легкий и очень нагруженный.
Первый вставляет запись и получает её айди, например, 13, который используется во втором запросе.
В тот момент, когда начал выполняться второй запрос, могла произойти вставка в таблицу, в которую добавлялась запись первым запросом.
Если бы эта конкурирующая вставка использовала "незанятый" айди 13, по которому записи ещё "как бы" не существует, то возникла бы коллизия, когда тяжёлый запрос выполнится: он уже использовал айди 13, но по факту этот айди принадлежит другой записи. Плюс, непонятно, куда коммитить первую запись из транзакции.
Ответ написан
Комментировать
@sidni
Php Developer
а почему бы не заменить
$user->getPrimaryKey();
на
$user->id;//где id это и есть Ваш primary key
и не плохо бы выложить код модели Token, почему в ней могут проблемы сохранения....
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы