使用select语句获取自动递增主键的最后一个值是否安全?

时间:2016-08-30 14:27:47

标签: c# sql sql-server concurrency

让我们假设SQL Server 2012中有以下简单表:

CREATE TABLE Person (
   Id INT IDENTITY(1, 1) PRIMARY KEY,
   Name NVARCHAR(50)
)

C#中的以下相应类:

public class Person 
{
    public int Id {get; set;}
    public string Name {get; set;}
}

现在考虑以下CreatePerson方法(伪代码):

public static Person CreatePerson(string name) {
    ...
    DB.Execute("INSERT INTO Person(Name) VALUES (name)", name);
    int lastId = DB.Get("SELECT MAX(Id) FROM Person");
    return new Person {Id = lastId, Name=name};
}

此方法在db中创建一个新的人员行,构建一个新的Person对象,然后返回应该包含数据库生成的Id的创建对象。

是否安全和/或正确(从并发角度来看)使用以下SELECT语句获取最后生成的ID?

SELECT MAX(Id) FROM Person

我担心以下情况:

  1. USER A 插入person 1
  2. 用户B 插入person 2
  3. 用户A 读取最后一个ID并认为它是person 1
  4. 的ID

    请注意这里的USER A和USER B是指处理对数据库的两个单独查询的线程。

2 个答案:

答案 0 :(得分:4)

如果您想获取该特定范围内的人员插入的最后一个身份值,请使用Scope_Identity()

如果您希望将最后一个标识值插入范围内的特定表格,则可以使用@@identity

如果您想获取特定表的当前标识值,请使用Ident_Current ('Yourtablename')

答案 1 :(得分:2)

不,它不安全,你可以使用这个程序进行数据插入,并使用scopre_Identity函数获取你的lastId

create PROCEDURE Your_procedure_for_insert
@Name      VARCHAR(50),
@lastID      INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;

INSERT INTO Person
            (
            Name                
            )
VALUES  
            (
            @Name 
            );

SET @lastID = SCOPE_IDENTITY();

END;