Идентификатор все еще увеличивается в базе данных после неудачного запроса - PullRequest
1 голос
/ 06 февраля 2012

Вот пример кода:

$sql = "INSERT INTO Users (Firstname,Surname) VALUES ('$firstname', '$surname')";

$stmt = sqlsrv_query( $conn, $sql,array(), array( "Scrollable" => SQLSRV_CURSOR_KEYSET ));
if(!$stmt) 
{
die('Yu feiru!');
}

В базе данных 3 столбца; ID, имя и фамилия. ID - это первичный ключ с автоинкрементом. У меня также есть имя в качестве уникального ключа. Итак, теперь, когда я все это рассмотрю, все объясняют мою проблему.

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

Вот проблема: если я сейчас вернусь к форме и отправлю ее с новыми подробностями, новая запись отобразит идентификатор 3. Так что проблема здесь в том, что каждый раз, когда я запускаю запрос, будет ли он успешным или нет, он увеличивает ID. Так что раньше, если бы я обновил страницу 5 раз, тогда новая запись имела бы идентификатор 7.

РЕДАКТИРОВАТЬ: Обратите внимание, как я уже сказал, это просто пример кода. Я до сих пор не принял никаких мер предосторожности против инъекций SQL. Независимо от этого, большое спасибо за ваши рекомендации.

Ответы [ 3 ]

1 голос
/ 06 февраля 2012

Я могу дать вам возможное решение.НО: во-первых, у вас есть ОЧЕНЬ мало причин для этого.Цель идентификатора - просто идентифицировать, а НЕ предоставлять реально-уникальную последовательность.Если вы хотите получить последовательность с уникальным промежутком, вы можете сделать это самостоятельно другим способом.

При этом добавьте триггер:

CREATE TRIGGER IdentityFixer
   ON  dbo.YourTable
   AFTER INSERT
AS 
BEGIN
declare @NextID bigint
set @NextID = (select MAX(MyID) from dbo.YourTable)
DBCC CHECKIDENT ("dbo.YourTable", RESEED, @NextID);
END
GO

Прекрасно решит указанную вами "проблему" (в Microsoft SQL Server).Вы можете вставить и потерпеть неудачу 1000 раз, но ваш идентификатор будет без пропусков.Я НЕ РЕКОМЕНДУЮ ЭТОГО.

1 голос
/ 06 февраля 2012

Это по замыслу. Столбец IDENTITY назначается при запуске INSERT каждой строки независимо от того, происходит ли COMMIT. Любые последующие вставки получат номера, которые гарантированно не конфликтуют. Любая или все транзакции могут быть неудачными или отменены. Без этой возможности вы не могли бы полагаться на столбец IDENTITY для работы с одновременными операциями.

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

0 голосов
/ 06 февраля 2012

Вы можете использовать транзакции SQL, фиксацию и откат, используя оператор try / catch, и это решит все проблемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...