beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Предварительное обсуждение найденных ошибок перед отправкой их авторам фреймворка, а также внесение новых предложений.
Закрыто
rkk
Сообщения: 40
Зарегистрирован: 2016.03.04, 19:33

beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение rkk »

Доброго времени суток всем.

Имеются две таблицы user_details и user_teachers, связанные через `user_id`.
В user_details - `user_id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`user_id`).
В user_teachers - `user_id` INT(11) NOT NULL.

В модели

Код: Выделить всё

    public function getTeacher()
    {
        if (($teacher = UserTeachers::findOne($this->user_id)) !== null) {
            return $this->hasOne(UserTeachers::className(), ['user_id' => 'user_id']);
        } else {
            return $this->teacher = new UserTeachers();
        }

    }
    
    public function setTeacher()
    {
        return $this->teacher = new UserTeachers();
    }
в контроллер создание записи

Код: Выделить всё

    public function actionCreate()
    {
        $model = new UserDetails();
        $transaction = Yii::$app->db->beginTransaction(); //0
        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            echo '$model->user_id: '.$model->user_id.'<br>';
            if($model->is_teacher){
                $model->teacher->user_id = $model->user_id;
                if ($model->teacher->load(Yii::$app->request->post())) {
                    $model->teacher->user_id = $model->user_id;
                    if ($model->teacher->save()) {
                        $transaction->commit(); //1
                        return $this->redirect(['view', 'id' => $model->user_id]);
                    }else{
                        $transaction->rollback(); //2
                        return $this->render('create', [
                            'model' => $model,
                        ]);
                    }
                }else{
                    $transaction->rollback(); //3
                    return $this->render('create', [
                        'model' => $model,
                    ]);
                }
            }
            $transaction->commit(); //4
            return $this->redirect(['view', 'id' => $model->user_id]);
        } else {
            echo '$model->user_id: '.$model->user_id.'<br>';
            $transaction->rollback(); //5
            return $this->render('create', [
                'model' => $model,
            ]);
        }
    }
так вот если у меня срабатывает $transaction->rollback(); //2 то $model->user_id увеличивается на единицу, соответственно сколько было попыток, на столько и увеличивается индекс.

Вопрос как это можно пофиксить или обойти? Чтобы индексы user_id шли по порядку.
Может через сессию, но какой-то костыль получается?
rak
Сообщения: 2181
Зарегистрирован: 2010.11.02, 23:40
Контактная информация:

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение rak »

это нормальное поведение mysql, yii тут не при чем
rkk
Сообщения: 40
Зарегистрирован: 2016.03.04, 19:33

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение rkk »

Спасибо!
Похоже раньше не замечал этого. Тогда, получается, лучше использовать сначала validate() вместо save(), а потом, если все нормально save().
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение zelenin »

save и так вызывает сначала validate
rkk
Сообщения: 40
Зарегистрирован: 2016.03.04, 19:33

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение rkk »

Да, но так я сначала исключаю, человеческий фактор, не верно введенные данные пользователем. Соответственно индекс не растет, пока пользователь пытается пропихнуть не валидные данные.
Так перед вызовом save я уже уверен, что все данные введены правильно и проблема которая может случиться, только в базе.

Пока переписал так, с индексом теперь норм:

Код: Выделить всё

    public function actionCreate()
    {
        $model = new UserDetails();
        
        // -------- сохранение  данных введенных в формах --------
        $model->load(Yii::$app->request->post());
        $model->teacher->user_id = 0;
        $model->teacher->load(Yii::$app->request->post());
        // -------- сохранение  данных введенных в формах --------
        
        if ($model->validate()) {
            if($model->is_teacher){
                $model->teacher->user_id = 0;
                if ($model->teacher->load(Yii::$app->request->post())) {
                    $model->teacher->user_id = 0;
                    if ($model->teacher->validate()) {
                        $transaction = Yii::$app->db->beginTransaction();
                        if($model->save()){
                            $model->teacher->user_id = $model->user_id;
                            if($model->teacher->save()){
                                $transaction->commit();
                                return $this->redirect(['view', 'id' => $model->user_id]);
                                
                            }
                            $transaction->rollback();
                            return $this->render('create', [
                                'model' => $model,
                            ]);
                        }
                        $transaction->rollback();
                        return $this->render('create', [
                            'model' => $model,
                        ]);
                    }else{
                        return $this->render('create', [
                            'model' => $model,
                        ]);
                    }
                }else{
                    return $this->render('create', [
                        'model' => $model,
                    ]);
                }
            }
            $model->save();
            return $this->redirect(['view', 'id' => $model->user_id]);
        } else {
            return $this->render('create', [
                'model' => $model,
            ]);
        }
    }
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение zelenin »

rkk писал(а):Да, но так я сначала исключаю, человеческий фактор, не верно введенные данные пользователем. Соответственно индекс не растет, пока пользователь пытается пропихнуть не валидные данные.
он и не будет расти. save запускает сначала validate, и если validate не прошел, то save не выполняется, и соответственно счетчик pk не увеличивается.
rkk писал(а):Так перед вызовом save я уже уверен, что все данные введены правильно и проблема которая может случиться, только в базе.
если счетчик увеличился, значит save запустился и прошел валидацию, а, значит, проблема в базе.
rkk писал(а):

Код: Выделить всё

    public function actionCreate()
    {
        $model = new UserDetails();
        
        // -------- сохранение  данных введенных в формах --------
        $model->load(Yii::$app->request->post());
        $model->teacher->user_id = 0;
        $model->teacher->load(Yii::$app->request->post());
        // -------- сохранение  данных введенных в формах --------
        
        if ($model->validate()) {
            if($model->is_teacher){
                $model->teacher->user_id = 0;
                if ($model->teacher->load(Yii::$app->request->post())) {
                    $model->teacher->user_id = 0;
                    if ($model->teacher->validate()) {
                        $transaction = Yii::$app->db->beginTransaction();
                        if($model->save()){
                            $model->teacher->user_id = $model->user_id;
                            if($model->teacher->save()){
                                $transaction->commit();
                                return $this->redirect(['view', 'id' => $model->user_id]);
                                
                            }
                            $transaction->rollback();
                            return $this->render('create', [
                                'model' => $model,
                            ]);
                        }
                        $transaction->rollback();
                        return $this->render('create', [
                            'model' => $model,
                        ]);
                    }else{
                        return $this->render('create', [
                            'model' => $model,
                        ]);
                    }
                }else{
                    return $this->render('create', [
                        'model' => $model,
                    ]);
                }
            }
            $model->save();
            return $this->redirect(['view', 'id' => $model->user_id]);
        } else {
            return $this->render('create', [
                'model' => $model,
            ]);
        }
    }
 
проблемы не решает
в момент вызова $model->save() у вас увеличивается счетчик, и вы присваиваете новые id связанной модели, но транзакция еще не завершена.
rak
Сообщения: 2181
Зарегистрирован: 2010.11.02, 23:40
Контактная информация:

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение rak »

да какая вообще разница что там с автоинкрементом происходит?
rkk
Сообщения: 40
Зарегистрирован: 2016.03.04, 19:33

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение rkk »

rak писал(а):да какая вообще разница что там с автоинкрементом происходит?
Да собственно никакой, просто люблю когда все по порядку. ;)
zelenin писал(а):
rkk писал(а): Да, но так я сначала исключаю, человеческий фактор, не верно введенные данные пользователем. Соответственно индекс не растет, пока пользователь пытается пропихнуть не валидные данные.
он и не будет расти. save запускает сначала validate, и если validate не прошел, то save не выполняется, и соответственно счетчик pk не увеличивается.
Это все верно для одной таблице, у меня же связанные 2 таблице. По условию добавляются дополнительные поля, которые надо сохранить во вторую таблицу.
Если использую save:
В первую таблицу данные проходят (пользователь ввел все верно), а во вторую не проходят (пользователь, что-то неправильно заполнил), то индекс в первой увеличивается на единицу, так как уже пошло обращение к базе.
Я эту проблему решил так, сначала использую validate и только потом
$model->save() и $model->teacher->save()

Если есть другое решение, пожалуйста, выслушаю.
caHek2x
Сообщения: 1242
Зарегистрирован: 2016.04.12, 20:41

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение caHek2x »

что вообще происходит ...
$model->teacher->load(Yii::$app->request->post());
проходит пару строк
if ($model->teacher->load(Yii::$app->request->post())) {
-------------------------------------
что такое teacher ? это hasOne ? а если там null ?)
-------------------------------------
зачем каждый раз return $this->redirect(['view', 'id' => $model->user_id]); ?
-------------------------------------
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение zelenin »

rkk писал(а):В первую таблицу данные проходят (пользователь ввел все верно), а во вторую не проходят (пользователь, что-то неправильно заполнил), то индекс в первой увеличивается на единицу, так как уже пошло обращение к базе.
Следим за мыслью:
rkk писал(а):Я эту проблему решил так, сначала использую validate и только потом
$model->save()
и счетчик увеличился независимо от того, выполнился ли второй запрос. Разницы ноль, т.к. $model->validate() && $model->save() и просто $model->save() одинаково увеличат счетчик при успешной валидации и не увеличат при неуспешной.
rkk
Сообщения: 40
Зарегистрирован: 2016.03.04, 19:33

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение rkk »

zelenin писал(а): Следим за мыслью:
rkk писал(а):Я эту проблему решил так, сначала использую validate и только потом
$model->save()
и счетчик увеличился независимо от того, выполнился ли второй запрос. Разницы ноль, т.к. $model->validate() && $model->save() и просто $model->save() одинаково увеличат счетчик при успешной валидации и не увеличат при неуспешной.
Логично для одной таблице, но где здесь запись во вторую ($model->teacher->save())?
caHek2x писал(а):что вообще происходит ...
$model->teacher->load(Yii::$app->request->post());
проходит пару строк
if ($model->teacher->load(Yii::$app->request->post())) {
-------------------------------------
что такое teacher ? это hasOne ? а если там null ?)
$model->teacher это hasOne. null там может быть, так как не для всех записей нужна эта связь.

Код: Выделить всё

    public function getTeacher()
    {
        if (($teacher = UserTeachers::findOne($this->user_id)) !== null) {
            return $this->hasOne(UserTeachers::className(), ['user_id' => 'user_id']);
        } else {
            return $this->teacher = new UserTeachers();
        }

    }
    
    public function setTeacher()
    {
        return $this->teacher = new UserTeachers();
    }
 
$model->teacher->load(Yii::$app->request->post()); это на случай если $model не прошел валидацию и в $model->teacher данные остались иначе они затирались.
Собственно тут наверно лучше изучать код в первом моем посте, этот код я написал что-бы исключить увеличение индекса. которое происходило когда $model->save проходил валивацию а $model->teacher->save не проходил валидацию.
Последний раз редактировалось rkk 2016.12.22, 17:16, всего редактировалось 1 раз.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение zelenin »

rkk писал(а):Логично для одной таблице, но где здесь запись во вторую ($model->teacher->save())?
а где у вас решена проблема для двух таблиц? Накостылили, но решили лишь частично. И кстати валидацию 4 раза дергаете.
rkk
Сообщения: 40
Зарегистрирован: 2016.03.04, 19:33

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение rkk »

zelenin писал(а):
rkk писал(а):Логично для одной таблице, но где здесь запись во вторую ($model->teacher->save())?
а где у вас решена проблема для двух таблиц? Накостылили, но решили лишь частично. И кстати валидацию 4 раза дергаете.
Точно надо вызывать save(false)
Спасибо.
rak
Сообщения: 2181
Зарегистрирован: 2010.11.02, 23:40
Контактная информация:

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение rak »

да уж, бедный человек, которому потом это поддерживать придется :shock:
caHek2x
Сообщения: 1242
Зарегистрирован: 2016.04.12, 20:41

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение caHek2x »

Код: Выделить всё

public function getTeacher()
{
    if (($teacher = UserTeachers::findOne($this->user_id)) !== null) {
        return $this->hasOne(UserTeachers::className(), ['user_id' => 'user_id']);
    } else {
        return $this->teacher = new UserTeachers();
    }
}
 
жестко :D
а потом в будущем вы прочитаете что такое with и joinWith ...
rkk
Сообщения: 40
Зарегистрирован: 2016.03.04, 19:33

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение rkk »

Что-то не пойму. Причем with и joinWith к транзакциям?
rak
Сообщения: 2181
Зарегистрирован: 2010.11.02, 23:40
Контактная информация:

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение rak »

rkk писал(а):Что-то не пойму. Причем with и joinWith к транзакциям?
а это был комментарий не про транзакции. а про те вот художества в методе getTeacher из приведенного выше кода
rkk
Сообщения: 40
Зарегистрирован: 2016.03.04, 19:33

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение rkk »

А чем такой подход плох? Раз его создали, значит надо пользоваться. Чем чревато?
rak
Сообщения: 2181
Зарегистрирован: 2010.11.02, 23:40
Контактная информация:

Re: beginTransaction при неудачной транзакции увеличивается PRIMARY KEY

Сообщение rak »

а кто создал то? тот, кто документацию плохо читал?
https://github.com/yiisoft/yii2/blob/ma ... и-данными- тут все прекрасно расписно
Закрыто