如何从数据库生成唯一的最大ID

时间:2014-04-07 19:09:24

标签: c# asp.net

我创建一个申请人注册表,其中申请人注册ID由"选择最大(ID)...."查询。当此查询从数据库中取出MaxID时,我将此ID增加一倍(+1),这样我为所有注册自己的申请人生成注册ID。但是当我从服务器和多个客户端运行我的项目时出现了一个问题(大约10个)申请人尝试注册然后存在"主键违规异常"发生了。执行Max Query后,将逐个执行5个Insert Query

代码在下面给出

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#

5 个答案:

答案 0 :(得分:1)

不要这样做,让数据库在您插入新行时为您生成密钥。例如,如何使用SQL ServerMySQL执行此操作。如果您确实想在客户端上执行此操作,请使用GUID作为键,因为您可以在不咨询数据库的情况下生成它们。将GUID作为键存在一些小问题,因为它们通常是部分随机的,这可能对聚簇索引产生负面的性能影响,但对于99.9%的所有数据库,它们都很好。

答案 1 :(得分:0)

  1. 解决方案1:
  2. 您可以创建一个只包含一列的表格,例如" GeneralID",并在您的应用程序中控制此ID以插入另一列。

    1. 解决方案2:
    2. 另一个解决方案是创建一个表,只有一个列,并且在插入之前触发每个表,以便将id转换为“#d; Ids表”#34;插入。

答案 2 :(得分:0)

在我们自动递增列之前,我们会有一个表来保存ID。它只有2列IdType varchar(10)和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没有更改,则只会在第二个语句中更新。如果确实改变了,它会再试一次。

答案 3 :(得分:0)

我不知道你什么时候将新值保存到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块中考虑此更新。

所有这一切,如果您不能使用Autonumbers但如果可以,请使用它。

答案 4 :(得分:0)

如果您可以在IDENTITY列中更改字段Temp_Applicant_RegNo,则无需担心分配给表Temp_Reg的下一个号码。这完全是你的数据库制作的jopb 您需要知道的是已分配的号码,并在后续插入中使用该号码 在

中插入后,可以使用SELECT SCOPE_IDENTITY()轻松完成此操作
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_IDENTITY()作为第二个查询添加到第一个插入,然后调用ExecuteScalar。 ExecuteScalar执行查询,然后返回上次执行的查询的第一行中第一列的值。