我创建一个申请人注册表,其中申请人注册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#
答案 0 :(得分:1)
不要这样做,让数据库在您插入新行时为您生成密钥。例如,如何使用SQL Server或MySQL执行此操作。如果您确实想在客户端上执行此操作,请使用GUID作为键,因为您可以在不咨询数据库的情况下生成它们。将GUID作为键存在一些小问题,因为它们通常是部分随机的,这可能对聚簇索引产生负面的性能影响,但对于99.9%的所有数据库,它们都很好。
答案 1 :(得分:0)
您可以创建一个只包含一列的表格,例如" GeneralID",并在您的应用程序中控制此ID以插入另一列。
另一个解决方案是创建一个表,只有一个列,并且在插入之前触发每个表,以便将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
您需要知道的是已分配的号码,并在后续插入中使用该号码
在
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执行查询,然后返回上次执行的查询的第一行中第一列的值。