C# 如何从数据库生成唯一的max id
我创建了一个申请者注册表单,其中申请者注册ID由Select MaxID生成。。。。查询当这个查询从数据库中取出MaxID时,我将这个ID加上1+1,这样我为所有注册自己的申请人生成一个注册ID。但有一个问题发生在我从服务器运行我的项目时,多个客户端大约有10个申请者试图注册,然后出现主键冲突异常。执行Max Query后,依次执行5个Insert查询 代码如下所示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
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会向每个客户端返回上次执行的查询的值。