Подтвердить что ты не робот

Как заставить mysql последний идентификатор вставки работать с транзакциями? + вопросы по сделке

Вопрос из двух частей:

  • В моем CodeIgniter script я начинаю транзакцию, а затем вставляю строку, устанавливая insert_id() в переменную php, вставляя больше строк в другую таблицу, используя новый идентификатор в качестве внешнего ключа, и затем я делаю все.

    Итак, мой вопрос: если все не фиксирует до окончания транзакции, как mysql может вернуть последний идентификатор вставки, если ничего не было вставлено? Мой script работает (почти) отлично, с новым ID, который используется в последующих запросах.

    (я говорю "почти", потому что, используя драйвер PDO mysql, иногда первая вставка, которая должна возвращать insert_id(), дублируется - она ​​вставлена ​​дважды. Любая идея, почему это было бы? получение последнего идентификатора? Это никогда не произойдет, если вы используете драйвер mysqli или mysql.)

  • Я сначала написал script без транзакций, поэтому у меня есть код, который проверяет ошибки mysql на этом пути, например:

    if(!$this->db->insert($table, $data)) {
        //log message here
    }
    

    Как это влияет на процесс mysql, как только я завернул весь мой код mysql в транзакции? Это не вызывает никаких видимых ошибок (надеюсь, не связанных с проблемой, указанной выше), но следует ли ее удалить?

Спасибо.

4b9b3361

Ответ 1

Чтобы ответить на ваш первый вопрос...

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

insert into number(Random_number) values (rand()); 
select Random_number from number where Number_id=Last_insert_id();

//PHP

if($num < 1)
   $this->db->query('rollback;'); // This number is too depressing.
else
   $this->db->query('commit;'); // This number is just right.

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

Если драйвер PDO не работает, попробуйте использовать драйвер mysqli. Если это не вариант, вы всегда можете использовать запрос "select last_insert_id() как id; а не функцию $this- > db- > insert_id().

Чтобы ответить на второй вопрос, если вы вставляете или обновляете данные, которые будут обновлять или считывать другие модели, обязательно используйте транзакции. Например, если столбец "Number_remaining" установлен в 1, может возникнуть следующая проблема.

Person A reads 1
Person B reads 1
Person A wins $1000!
Person A updates 1 to be 0
Person B wins $1000!
Person B updates 0 to be 0

Использование транзакций в той же ситуации даст следующий результат:

Лицо A начинает транзакцию
Лицо A читает "1" из Number_remaining
(строка теперь заблокирована, если используется выбрать для обновления) Лицо B попытки прочитать Number_remaining - заставили ждать
Лицо A побеждает $1000
Лицо Обновления 1, чтобы быть 0
Лицо А совершает
Лицо B читает 0
Лицо B не выигрывает $1000
Лицо B кричит

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

Будьте осторожны с тупиком, который может произойти в этом случае:

Лицо A читает строку 1 (select ... for update)
Лицо B читает строку 2 (select ... for update)
Лицо A пытается прочитать строку 2, заставил ждать
Person B пытается прочитать строку 1, заставил ждать
Лицо A достигает innodb_lock_wait_timeout (по умолчанию 50 секунд) и отключен
Person B читает строку 1 и продолжает нормально

В конце концов, поскольку Person B, вероятно, достиг PHP max_execution_time, текущий запрос завершит выполнение независимо от PHP, но дальнейшие запросы не будут получены. Если это была транзакция с autocommit = 0, запрос автоматически откатится, когда соединение с вашим сервером PHP будет разорвано.