【问题标题】:Stored procedure occasionally executes twice存储过程偶尔会执行两次
【发布时间】:2014-08-28 14:36:00
【问题描述】:

我创建了一个 .net 控制台应用程序,它从计算机和/用户那里收集一些基本的库存信息。它通过存储过程将此信息转储到 SQL Server 2012 数据库中。

我偶尔会在至少两个表中出现重复记录。

存储过程非常简单,当存储过程接收到序列号(以及其他参数)时,它会在资产表中搜索序列号。如果找到匹配项,则返回 assetId,否则将创建一个新条目并返回新创建的 assetId。同样在该过程中,使用先前返回的assetId 将日期时间条目添加到事件表中。

我开始看到的是资产表中的两条记录,它们具有连续的assetId 编号,但具有相同的序列号。有趣的是,事件表中将有两条记录对应于这些assetId中的每一个,它们具有完全相同的date_time

在我们拥有的 22,000 多台计算机中,这仅发生在五个序列号上,因此对我来说这并不是世界末日。但是,因为这个问题,我被质疑其余数据的可靠性。

任何想法如何发生?

存储过程

    --Create an asset row if there is not one and retrieve the id. Or just retrieve the id.
If (select count(assetid) from asset where serial=@serial) > 0
Begin
    set @assetid = (select top 1 assetid from asset where serial=@serial )
End
Else 
    --Add asset to table
    Begin
        Insert into asset (serial, model, manufacturer) 
        values (@serial, @model, @manufacturer);

        set @assetid = (Select SCOPE_IDENTITY())
    End
    --End Asset entry

    --Insert Audit Event record
    Insert into auditevent (assetid, audittime, username, computername, operatingsystem) 
    values (@assetid, @audittime, @username, @computername, @operatingsystem)

    Declare @auditeventid int = (select SCOPE_IDENTITY())

    --Send the ipString to the function that will convert it to a table and insert into IP Table
    Insert into ipaddress (auditeventid, ipaddress) 
        select * 
        from CsvToTable(@auditeventid, @ipaddressvalues)

控制台应用(单线程)

    Dim strExcutionCommand As String = "dbo.auditclient @computername=N'" & strComputerName & "',@modeltext=N'" & strModel & "',@serial=N'" & strSerialNumber & "',@username=N'" & strUserName & "',@manufacturertext=N'" & strManufacturer & "',@operatingsystemtext=N'" & strOperatingSystem & "',@ipaddressvalues=N'" & strNetAddress & "'"


    Dim Inv_ConnectString As String = "Data Source=cen-support01;Initial Catalog=IT_Inventory;User Id=" & strSqlUser & ";Password=" & strSqlPw & ";"
    Dim myConnection As SqlConnection = New SqlConnection(Inv_ConnectString)

    Dim myCommand As SqlCommand = New SqlCommand(strExcutionCommand, myConnection)
    myConnection.Open()
    myCommand.ExecuteNonQuery()
    myConnection.Close()

【问题讨论】:

  • 你为什么要从应用程序审计,这是一个数据库反模式?
  • 我建议将asset.assetid 设为主键以避免重复,即使其他地方存在错误。我还建议用 begin transaction / commit 包装你的所有陈述。
  • 顺便说一句,我认为问题在于调用存储过程的控制台应用程序,或者如何触发控制台应用程序执行。
  • @HLGEM 我不知道有什么其他方法可以快速完成任务。我考虑过服务器驱动的模型,但需要更多的代码和调试,这 = 时间。什么是更好的模型?
  • @wdosanjos asset.assetid 实际上是 PK。我认为的重复记录实际上是不同的,因为assetid字段增加了1。

标签: .net sql-server stored-procedures


【解决方案1】:

如果不查看控制台应用程序的代码及其运行方式的详细信息,就很难诊断此问题。例如,您能否运行多个实例并让 2 个线程尝试同时执行相同的任务?

当有要添加的库存项目时,您可以通过运行控制台应用程序两次来测试这是否是原因,并查看它是否重复。

存储过程的逻辑看起来不错,虽然我会稍微重写一下:

IF EXISTS (SELECT 1 FROM asset WHERE serial=@serial) 
   -- Create an asset row if it doesn't exist
    BEGIN
        SELECT @assetid = assetid FROM asset WHERE serial=@serial
    END
ELSE 
    --Add asset to table    
    BEGIN
        INSERT INTO asset (serial,model,manufacturer) 
        VALUES (@serial,@model,@manufacturer);

        SELECT @assetid = SCOPE_IDENTITY()
    END

这是未经测试的,但你应该明白。

【讨论】:

  • 见上面我添加的控制台代码。这是一个非常简单的程序。它是单线程的,因此不会两次运行任何函数。它从 WMI 收集数据,存储到变量并通过存储过程保存到数据库。
猜你喜欢
  • 2015-11-22
  • 2014-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多