C# 如何从数据库生成唯一的max id

C# 如何从数据库生成唯一的max id,c#,asp.net,C#,Asp.net,我创建了一个申请者注册表单,其中申请者注册ID由Select MaxID生成。。。。查询当这个查询从数据库中取出MaxID时,我将这个ID加上1+1,这样我为所有注册自己的申请人生成一个注册ID。但有一个问题发生在我从服务器运行我的项目时,多个客户端大约有10个申请者试图注册,然后出现主键冲突异常。执行Max Query后,依次执行5个Insert查询 代码如下所示 public long getUid() { try { stri

我创建了一个申请者注册表单,其中申请者注册ID由Select MaxID生成。。。。查询当这个查询从数据库中取出MaxID时,我将这个ID加上1+1,这样我为所有注册自己的申请人生成一个注册ID。但有一个问题发生在我从服务器运行我的项目时,多个客户端大约有10个申请者试图注册,然后出现主键冲突异常。执行Max Query后,依次执行5个Insert查询

代码如下所示

public long getUid()
    {
        try
        {
            string qry = "select isnull(max(Temp_Applicant_RegNo),0) as appregno FROM Temp_Reg";
            if (cs.State == ConnectionState.Closed)
            {
                cs.Open();
            }
            cmd = new SqlCommand(qry, cs);
            dr = cmd.ExecuteReader();
            long cid = 0;
            if (dr.Read())
            {
                cid = long.Parse(dr["appregno"].ToString());
                cid++;
            }
            if (cs.State == ConnectionState.Open)
            {
                cs.Close();
            }
            return cid;
        }
        catch (Exception ex)
        {
            lbl_ErrorMsg.Text = ex.Message; 
            return 0;
        }
    }



protected void Save_btn_Click(object sender, EventArgs e)
    {
        SqlTransaction trn = null;
        try
        {
             long Regid = getUid();      
             con.Open();
             trn = con.BeginTransaction();

             cmd = new SqlCommand("insert into....", con, trn);
             cmd.Parameters.AddWithValue("@RegNo", Regid);
             cmd.ExecuteNonQuery();

             cmd = new SqlCommand("insert into....", con, trn);
             cmd.Parameters.AddWithValue("@RegNo", Regid);
             cmd.ExecuteNonQuery();

             cmd = new SqlCommand("insert into....", con, trn);
             cmd.Parameters.AddWithValue("@RegNo", Regid);
             cmd.ExecuteNonQuery();

             trn.Commit();
         }
        catch (Exception ex)
        {
            lbl_ErrorMsg.Text = ex.Message;
            trn.Rollback();
        }
 }                 
请给我建议,我如何才能为申请人生成最大ID,这样就不会有任何重复的机会。因为我在现场项目中工作


在这里,我使用的是Asp.net C

不要这样做,在插入新行时,让数据库为您生成密钥。下面是如何使用或执行此操作的示例。如果您真的想在客户机上执行此操作,请使用guid作为键,因为您可以在不咨询数据库的情况下生成它们。guid作为键存在一些小问题,因为它们通常是部分随机的,这可能会对聚集索引的性能产生负面影响,但对于99.9%的数据库来说,它们还可以

解决方案1: 您可以创建一个只包含一列的表,例如GeneralID,并在您的应用程序控件中将此Id插入到其他表中

解决方案2:
另一种解决方案是创建一个表和一个列,并在插入之前为每个表创建一个触发器,以普及id,从而获得要插入的id表。

在拥有自动递增列之前,我们将有一个表来保存id。它只有两列IdType varchar10和NextId int。然后在存储过程中,我们会有如下内容:

while(1=1)
begin
    select @nextId = nextId
    from MyIds
    where IdType=@IdType

    update MyIds
    set nextId = @nextId + 1
    where IdType=@IdType
    and nextId = @nextId

    if(@@ROWCOUNT > 0)
        break;
end 

select @nextId as nextId

注意,只有在nextId没有改变的情况下,才会在第二条语句中更新。如果确实发生了更改,它将重试。

我不知道您何时将新值保存到Temp_Reg,但是如果您在计算后立即保存该值,您将如何安全地更新其他表:

public long getUid()
{
    try
    {
        string qry = "select isnull(max(Temp_Applicant_RegNo),0) as appregno FROM Temp_Reg";
        if (cs.State == ConnectionState.Closed)
        {
            cs.Open();
        }
        cmd = new SqlCommand(qry, cs);
        dr = cmd.ExecuteReader();
        long cid = 0;
        if (dr.Read())
        {
            cid = long.Parse(dr["appregno"].ToString());
            cid++;
        }

UPDATE Temp_reg HERE !!!!

        if (cs.State == ConnectionState.Open)
        {
            cs.Close();
        }
        return cid;
    }
    catch (Exception ex)
    {
        lbl_ErrorMsg.Text = ex.Message; 
        return 0;
    }
}
然后,您必须在Save_btn_Click的catch块中考虑此更新


如果您不能使用自动编号,但如果可以,请使用它。

如果您可以在标识列中更改字段Temp\u applicator\u RegNo,则无需担心分配给表Temp\u Reg的下一个编号。这都是由数据库制作的jopb。 您只需要知道分配了什么号码,并在后续插入中使用该号码。 这可以很容易地在插入后使用

protected void Save_btn_Click(object sender, EventArgs e)
{
    SqlTransaction trn = null;
    try
    {
         con.Open();
         trn = con.BeginTransaction();

         cmd = new SqlCommand("insert into....; SELECT SCOPE_IDENTITY()", con, trn);
         int Regid = Convert.ToInt32(cmd.ExecuteScalar());

         cmd = new SqlCommand("insert into....", con, trn);
         cmd.Parameters.AddWithValue("@RegNo", Regid);
         cmd.ExecuteNonQuery();

         cmd = new SqlCommand("insert into....", con, trn);
         cmd.Parameters.AddWithValue("@RegNo", Regid);
         cmd.ExecuteNonQuery();

         trn.Commit();
     }
    catch (Exception ex)
    {
        lbl_ErrorMsg.Text = ex.Message;
        trn.Rollback();
    }

技巧是将SELECT SCOPE_标识作为第二个查询添加到第一个insert,然后调用ExecuteScalar。ExecuteScalar执行查询,然后返回上次执行的查询第一行中第一列的值

不要选择MAXID,然后增加它。在主键中使用标识,以便数据库为您生成密钥。如果您使用的是SQL Server 2012/2014,另一个选项是使用序列。好的,我将尝试。但当多个客户端同时交互时会发生什么呢?意味着如果有两个或多个用户同时交互,则SCOPE_IDENTITY会向每个客户端返回上次执行的查询的值。