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

MySQL AUTO_INCREMENT не ROLLBACK

Я использую поле MySQL AUTO_INCREMENT и InnoDB для поддержки транзакций. Я заметил, что когда я откатываю транзакцию, поле AUTO_INCREMENT не отменяется? Я узнал, что он был разработан таким образом, но есть ли какие-то обходные пути?

4b9b3361

Ответ 1

Позвольте мне указать на что-то очень важное:

Вы никогда не должны зависеть от числовых функций автогенерированных ключей.

То есть, кроме сравнения их для равенства (=) или неравномерности (< gt;), вы не должны делать ничего другого. Нет реляционных операторов (<, gt;), нет сортировки по индексам и т.д. Если вам нужно сортировать по "добавленной дате", укажите столбец с добавленной датой.

Относитесь к ним как к яблокам и апельсинам. Имеет ли смысл спрашивать, совпадает ли яблоко с апельсином? Да. Имеет ли смысл спрашивать, больше ли яблоко, чем апельсин? Нет. (На самом деле, да, но вы понимаете мою точку зрения.)

Если вы придерживаетесь этого правила, пробелы в непрерывности автоматически генерируемых индексов не вызовут проблем.

Ответ 2

Он не может работать таким образом. Рассмотрим:

  • запрограммируйте один, вы открываете транзакцию и вставляете в таблицу FOO, у которой есть первичный ключ autoinc (произвольно, мы говорим, что он получает 557 за его ключевое значение).
  • Запуск программы начинается, она открывает транзакцию и вставляет в таблицу FOO, получая 558.
  • Вставьте две вставки в таблицу BAR, в которой есть столбец, который является внешним ключом для FOO. Итак, теперь 558 находится как в FOO, так и в BAR.
  • Теперь выполняются две программы.
  • Программа три запускает и создает отчет из таблицы FOO. Запись 558 будет напечатана.
  • После этого программа перевернется.

Как база данных восстанавливает значение 557? Он переходит в FOO и уменьшает все остальные первичные ключи, превышающие 557? Как установить BAR? Как он удаляет 558, напечатанных в программе отчетов, три выхода?

Номера последовательностей Oracle также не зависят от транзакций по той же причине.

Если вы можете решить эту проблему в постоянное время, я уверен, что вы можете заработать много денег в поле базы данных.

Теперь, если у вас есть требование, чтобы в вашем поле автоматического прироста никогда не было пробелов (например, для целей аудита). Тогда вы не сможете откатить свои транзакции. Вместо этого вам нужно иметь флаг состояния в ваших записях. При первой вставке статус записи "Неполный", тогда вы начинаете транзакцию, выполняете свою работу и обновляете статус, чтобы "конкурировать" (или все, что вам нужно). Затем, когда вы совершаете фиксацию, запись активна. Если транзакция отката, то для аудита все еще существует неполная запись. Это вызовет много головных болей, но это один из способов борьбы с аудиторскими трассами.

Ответ 3

Мне нужен клиент для отката в таблице счетов-фактур, где заказ должен быть последовательным

Мое решение в MySQL заключалось в том, чтобы удалить AUTO-INCREMENT и вытащить последний идентификатор из таблицы, добавить один (+1) и затем вставить его вручную.

Если таблица называется "TableA", а столбец "Auto-increment" равен "Id"

INSERT INTO TableA (Id, Col2, Col3, Col4, ...)
VALUES (
(SELECT Id FROM TableA t ORDER BY t.Id DESC LIMIT 1)+1,
Col2_Val, Col3_Val, Col4_Val, ...)

Ответ 4

Почему вас это волнует, если он откат? Ключевые поля AUTO_INCREMENT не должны иметь никакого значения, поэтому вам действительно не стоит заботиться о том, какое значение используется.

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

Ответ 5

Я не знаю, как это сделать. Согласно Документация MySQL, это ожидаемое поведение и произойдет со всеми режимами блокировки innodb_autoinc_lock_mode. Конкретный текст:

Во всех режимах блокировки (0, 1 и 2), если транзакция, которая значения автоинкремента отбрасываются, эти значения автоинкремента "потерял." Когда значение генерируется для столбец автоинкремента, он не может быть откатывается, независимо от того, Заявление "INSERT-like" завершено, и независимо от того, содержит ли транзакция откат. Такие потерянные значения не используются повторно. Таким образом, быть пробелами в значениях, хранящихся в Столбец AUTO_INCREMENT таблицы.

Ответ 6

Если вы установите auto_increment на 1 после откат или удаления, в следующей вставке MySQL увидит, что 1 уже используется и вместо этого получит значение MAX() и добавит 1 к нему.

Это гарантирует, что если строка с последним значением будет удалена (или вставка будет откат), она будет повторно использована.

Чтобы установить auto_increment в 1, сделайте что-то вроде этого:

ALTER TABLE tbl auto_increment = 1

Это не так эффективно, как просто продолжение следующего номера, потому что MAX() может быть дорогостоящим, но если вы удаляете/откатываете нечасто и одержимы повторным использованием самого высокого значения, то это реалистичный подход.

Помните, что это не мешает удалению пробелов из записей в середине или если другая вставка должна произойти до того, как вы установите auto_increment на 1.

Ответ 7

INSERT INTO prueba(id) 
VALUES (
(SELECT IFNULL( MAX( id ) , 0 )+1 FROM prueba target))

Если таблица не содержит значений или нулевых строк

добавить цель для ошибки mysql type update FROM on SELECT

Ответ 8

РЕШЕНИЕ:

Позвольте использовать "tbl_test" в качестве примерной таблицы и предположим, что поле "Id" имеет атрибут AUTO_INCREMENT

CREATE TABLE tbl_test (
Id int NOT NULL AUTO_INCREMENT ,
Name varchar(255) NULL ,
PRIMARY KEY (`Id`)
)
;

Предположим, что таблица содержит или уже вставлена ​​тысяча строк, и вы больше не хотите использовать AUTO_INCREMENT; потому что когда вы откатываете транзакцию, поле "Id" всегда добавляет +1 к значению AUTO_INCREMENT. Поэтому, чтобы избежать этого, вы можете сделать это:

  • Позвольте удалить значение AUTO_INCREMENT из столбца "Id" (это не приведет к удалению вставленных строк):
ALTER TABLE tbl_test MODIFY COLUMN Id  int(11) NOT NULL FIRST;
  • Наконец, мы создаем триггер ДО НАЧАЛА ВСТАВКИ, чтобы автоматически генерировать значение "Id". Но использование этого способа не повлияет на ваше значение идентификатора, даже если вы откатите какую-либо транзакцию.
CREATE TRIGGER trg_tbl_test_1
BEFORE INSERT ON tbl_test
FOR EACH ROW
  BEGIN
    SET NEW.Id= COALESCE((SELECT MAX(Id) FROM tbl_test),0) + 1;
  END;

Что это! Все готово!

Добро пожаловать.

Ответ 9

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

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

Ответ 10

Конкретный ответ на эту конкретную дилемму (которая у меня также была):

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

2) Перед созданием нового документа выполните следующие действия (например, для счетов-фактур):

UPDATE document_counters SET counter = LAST_INSERT_ID(counter + 1) where type = 'invoice'

3) Получите последнее значение, которое вы только что обновили, например:

SELECT LAST_INSERT_ID()

или просто используйте функцию PHP (или что-то еще) mysql_insert_id(), чтобы получить то же самое

4) Вставьте новую запись вместе с основным идентификатором, который вы только что вернули из БД. Это будет отменять текущий индекс автоматического инкремента и убедитесь, что у вас нет пробелов идентификатора между вашими записями.

Все это нужно, конечно, обернуть внутри транзакции. Красота этого метода заключается в том, что при откат транзакции ваш оператор UPDATE с шага 2 будет откат, и счетчик больше не изменится. Другие параллельные транзакции будут блокироваться до тех пор, пока первая транзакция не будет выполнена или не будет отменена, чтобы у них не было доступа ни к старому счетчику, ни к другому, пока все другие транзакции не будут выполнены в первую очередь.

Ответ 11

$masterConn = mysql_connect("localhost", "root", '');
mysql_select_db("sample", $masterConn);

for($i=1; $i<=10; $i++) {
    mysql_query("START TRANSACTION",$masterConn);
    $qry_insert = "INSERT INTO 'customer' (id, 'a', 'b') VALUES (NULL, '$i', 'a')";
    mysql_query($qry_insert,$masterConn);
    if($i%2==1) mysql_query("COMMIT",$masterConn);
    else mysql_query("ROLLBACK",$masterConn);

    mysql_query("ALTER TABLE customer auto_increment = 1",$masterConn);

}



echo "Done";