C# 更新sql返回0行后,插入sql中立即发生违反主键约束的错误
我有这样的代码C# 更新sql返回0行后,插入sql中立即发生违反主键约束的错误,c#,sql,sql-server,C#,Sql,Sql Server,我有这样的代码 if (***Adapter.UpdateRow(memberID, Type) == 0) { ***Adapter.InsertRow(memberID, Type); } 但是我在InsertRow中得到了违反主键约束的错误。 表中的主键是memberID和Type,下面是SQL: InsertRow string sql = @" INSERT INTO TB
if (***Adapter.UpdateRow(memberID, Type) == 0)
{
***Adapter.InsertRow(memberID, Type);
}
但是我在InsertRow中得到了违反主键约束的错误。
表中的主键是memberID和Type,下面是SQL:
InsertRow
string sql = @"
INSERT INTO TBL***** (
MemberID
, Type
, DateTime
)
VALUES (
@MemberID
, @Type
, GETDATE()
)
";
var cm = new SqlCommand(sql.ToString());
cm.Parameters.Add("@MemberID", SqlDbType.Int).Value = memberID;
cm.Parameters.Add("@Type", SqlDbType.Int).Value = (int)Type;
return this.ExecuteNonQuery(cm);
string sql = @"
UPDATE TBL****
SET DateTime = GETDATE()
WHERE MemberID = @MemberID
AND Type = @Type
";
var cm = new SqlCommand(sql.ToString());
cm.Parameters.Add("@MemberID", SqlDbType.Int).Value = memberID;
cm.Parameters.Add("@Type", SqlDbType.Int).Value = (int)Type;
return this.ExecuteNonQuery(cm);
UpdateRow
string sql = @"
INSERT INTO TBL***** (
MemberID
, Type
, DateTime
)
VALUES (
@MemberID
, @Type
, GETDATE()
)
";
var cm = new SqlCommand(sql.ToString());
cm.Parameters.Add("@MemberID", SqlDbType.Int).Value = memberID;
cm.Parameters.Add("@Type", SqlDbType.Int).Value = (int)Type;
return this.ExecuteNonQuery(cm);
string sql = @"
UPDATE TBL****
SET DateTime = GETDATE()
WHERE MemberID = @MemberID
AND Type = @Type
";
var cm = new SqlCommand(sql.ToString());
cm.Parameters.Add("@MemberID", SqlDbType.Int).Value = memberID;
cm.Parameters.Add("@Type", SqlDbType.Int).Value = (int)Type;
return this.ExecuteNonQuery(cm);
我现在真的很想知道它发生的原因(就在更新之后)
谢谢大家的评论。 我认为可能有两个线程相互冲突,然后第一个线程成功插入,但第二个线程失败 我在我的网站的用户注册中有这样的逻辑,当用户点击注册邮件中的激活链接时就会发生。
我认为用户可能会(以高速)双击链接,然后出现错误。违反主键约束意味着您试图插入一条记录,该记录将在主键字段上创建重复项 检查表定义并注意主键中的字段 如果您可以将问题中的表定义发布给其他读者,效果会更好:) 添加评论后编辑 如果您的主键同时包含MemberId和Type,则更新中可能存在逻辑错误,或者存在更新中不返回结果的情况 您应该按照建议使用upsert(更新或插入) 逻辑如下:
您通常不会执行更新来检查记录是否存在,因为在某些情况下,更新可能不会执行任何更改。您的代码依赖于执行DML后返回的行数。这不一定会发生,因为这取决于设置。当“设置无计数”处于启用状态时 返回的行数始终为0,与实际更新的行数无关。返回的行数是
ExecuteNonQuery()
返回的
您可以检查并确保SETNOCOUNT已关闭,但这仍然是一个失败的原因。您提出的代码在并发性方面存在根本性缺陷:多个客户端应用程序可以同时运行更新,并且所有客户端应用程序都认为应该插入,然后只有一个客户端应用程序会成功。正确的方法是使用以下语句:
MERGE INTO TBL**** as t
USING (VALUES (GETDATE(), @MemberId, @Type)) AS s (date, MemberID, Type)
ON t.MemberID =s.MemberID and t.Type = s.Type
WHEN MATCHED THEN
UPDATE SET t.DateTime = s.date
WHEN NOT MATCHED BY TARGET
INSERT (MemberID, Type, DateTime) VALUES (s.MemberID, s.Type, s.DateTime);
这是一条语句,它确实会使插入或更新失效,而不会产生并发风险。主键是什么?是否尝试运行Sql Server Profiler跟踪?是否检查日志等以查看更新是否返回错误?在显示代码逻辑的情况下,如果更新有错误并返回0行更新,则将尝试插入。您可能需要重新考虑一下。将两个查询合并为一个“UpdateOrInsert”,并使用“IF EXISTS”检查是否要更新或插入。感谢您的回答。这是我的表定义,来自脚本工具(键的一部分)ALTER table[dbo]。[TBLLogin]ADD CONSTRAINT[PK_TBLLogin]主键集群([MemberID]ASC,[Type]ASC)(PAD_INDEX=OFF,STATISTICS_norecocomputer=OFF,SORT_IN_TEMPDB=OFF,IGNORE_DUP_KEY=OFF,ONLINE=OFF,ALLOW_ROW_LOCKS=ON,ALLOW_PAGE_LOCKS=ON)打开[主]GO