查询失败后,ID仍会在数据库中递增

时间:2012-02-06 19:00:04

标签: php sql sql-server database

以下是一些示例代码:

$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是自动增量主键。我也将firstname作为唯一键。所以,既然我已经把这一切都放到了眼前,那么所有这些都解释了我的问题。

当我的表单完成后,如果上面的代码被执行,则转到页面。现在,最初这是正常的,所以现在我将在表中将我的第一条记录ID为1.现在,如果我要刷新此页面它会返回错误,这显然是因为我插入了相同的firstname,因为它是一个独特的键,所以它不会起作用,所以这么好。

问题是,如果我现在要返回到表单并提交新的详细信息,新记录显示ID为3.所以问题在于每次运行查询时,是否成功或不,它增加ID。所以之前,如果我要刷新页面5次,那么新记录的ID将为7。

编辑:请注意,正如我所说,这只是示例代码。我仍然没有采取任何针对SQL注入的预防措施。无论如何,非常感谢您的推荐。

3 个答案:

答案 0 :(得分:1)

我可以给你一个可能的解决方案。但是:首先,你很少有理由想要这样做。 ID的目的只是识别,而不是提供可靠的唯一序列。如果你想要一个无间隙的独特序列,你可以用其他方式自己做。

话虽如此,添加此触发器:

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次,仍然你的id将无间隙。我不推荐这个。

答案 1 :(得分:1)

这是设计的。无论是否发生COMMIT,都会在启动每行的INSERT时分配IDENTITY列。任何后续的INSERT都将获得保证不会发生冲突的数字。任何或所有交易都可能失败或被回滚。如果没有此功能,您将无法依赖IDENTITY列来同时执行操作。

我强烈质疑任何需要不间断序列的设计目标。这些事情很少是真正必要的。我发现请求通常来自审计需求或某种设计,它们喜欢假设某种行数/行数相关性。通常,可以在不依赖于此类事物的情况下实施强大的审计功能。

答案 2 :(得分:0)

您可以使用try / catch语句来使用SQL事务,提交和回滚,这将解决所有问题。