【问题标题】:Windows service using VB.NET doesn't work?使用 VB.NET 的 Windows 服务不起作用?
【发布时间】:2021-04-15 13:31:48
【问题描述】:

我的程序应该做什么:我的目标是创建一个 Windows 服务,它充当多个 SQL 数据库之间的中介。总共有 3 个不同的表在 3 个不同的服务器上。详细地说,当这个服务运行时,它应该监督“表 1”中的数据,并定期(每 1 分钟)将其复制到“表 2”。但棘手的部分是它不能粘贴重复记录,必须检查 "Table2" 的 ID 字段并验证是否没有粘贴具有相同 ID 的相同记录。I've added a diagram for understanding purposes of what my goal is

我做了什么:到目前为止,我已经完全开发了代码,但问题是它只从一个表中复制数据(根据我所附的图表,特别是“NOR_LABOR”)到“MES_DEV”数据库中的“DEV_Test_Nor_Data”(con1 到 con2)。根据图con1、con3、con4分别是表“NOR_LABOR”、“SETTER_LABOR”和“wrap_labor”。 con2 是“MES_DEV”数据库的目的地。

谁能弄清楚为什么其他表的数据(con3 to con2 & con4 to con2)不会复制?

我的代码 - 数据收集器

Imports System.Configuration
Imports System.Data.SqlClient

Public Class DataCollector

    Dim con1, con2, con3, con4 As New SqlConnection
    Dim timer1 As Timers.Timer
    Dim p_oConn As New Wisys.AllSystem.ConnectionInfo
    Protected Overrides Sub OnStart(ByVal args() As String)

        con1 = New SqlConnection("Data Source=NORMAC-CTMS\SQLEXPRESS;Database=Normac Data;Integrated Security=true")
        con1.Open()
        con2 = New SqlConnection("Data Source=STLEDGSQL01;Database=MES_DEV;Integrated Security=true")
        con2.Open()
        con3 = New SqlConnection("Data Source=201706-SETTER1\SQLEXPRESS;Database=Edge;Integrated Security=true")
        con3.Open()
        con4 = New SqlConnection("Data Source=PRINTER\SQLEXPRESS;Database=Wrapper Data;Integrated Security=true")
        con4.Open()

        timer1 = New Timers.Timer()
        timer1.Interval = 5000
        AddHandler timer1.Elapsed, AddressOf OnTimedEvent
        timer1.Enabled = True
        FileIO.WriteLog("Service has started")

    End Sub

    Protected Overrides Sub OnStop()
        timer1.Enabled = False
        FileIO.WriteLog("Service has stopped")
        con1.Close()
        con2.Close()
        con3.Close()
        con4.Close()
    End Sub


    Private Sub OnTimedEvent(obj As Object, e As EventArgs)

        Dim cmd1, cmd2, cmd3 As SqlCommand

        'Connecting the Normac Data table
        Dim da1 As SqlDataAdapter = New SqlDataAdapter("select ID, trx_date, work_order, department, work_center, operation_no, operator, total_labor_hours, feet_produced, item_no, posted, labor_feet_produced from NOR_LABOR", con1)
        Dim cb1 As SqlCommandBuilder = New SqlCommandBuilder(da1)
        Dim dt1 As DataTable = New DataTable()
        da1.Fill(dt1)

        'Connecting the Setter_Labor table
        Dim da2 As SqlDataAdapter = New SqlDataAdapter("select ID, trx_date, work_order, department, work_center, operation_no, operator, total_labor_hours, labor_feet_produced, item_no, posted from Setter_Labor", con3)
        Dim cb2 As SqlCommandBuilder = New SqlCommandBuilder(da2)
        Dim dt2 As DataTable = New DataTable()
        da2.Fill(dt2)

        'Connecting the Wrap_Labor table
        Dim da3 As SqlDataAdapter = New SqlDataAdapter("select ID, trx_date, work_order, Department, work_center, operation_no, operator, total_labor_hrs, job_start, job_end, qty_ordered, qty_produced, item_no, lot_no, default_bin, posted, wrapped, total_shift_hrs, check_emp, machine, operation_complete from wrap_labor", con4)
        Dim cb3 As SqlCommandBuilder = New SqlCommandBuilder(da3)
        Dim dt3 As DataTable = New DataTable()
        da3.Fill(dt3)


        Dim i, j, k As Integer

        'Inserting into DEV_Test_Nor_Data table
        For Each dr As DataRow In dt1.Rows

            cmd1 = New SqlCommand("Insert into DEV_Test_Nor_Data values('" & dr(0) & "','" & dr(1) & "','" & dr(2) & "','" & dr(3) & "','" & dr(4) & "','" & dr(5) & "','" & dr(6) & "','" & dr(7) & "','" & dr(8) & "','" & dr(9) & "','" & dr(10) & "','" & dr(11) & "')", con2)
            i = cmd1.ExecuteNonQuery()


        Next

        'Inserting into DEV_Test_Set_Lbr table
        For Each dr As DataRow In dt2.Rows

            cmd2 = New SqlCommand("Insert into DEV_Test_Set_Lbr values('" & dr(0) & "','" & dr(1) & "','" & dr(2) & "','" & dr(3) & "','" & dr(4) & "','" & dr(5) & "','" & dr(6) & "','" & dr(7) & "','" & dr(8) & "','" & dr(9) & "','" & dr(10) & "')", con2)
            j = cmd2.ExecuteNonQuery()

        Next

        'Inserting into DEV_Test_Wrp_Lbr table
        For Each dr As DataRow In dt3.Rows

            cmd3 = New SqlCommand("Insert into DEV_Test_Wrp_Lbr values('" & dr(0) & "','" & dr(1) & "','" & dr(2) & "','" & dr(3) & "','" & dr(4) & "','" & dr(5) & "','" & dr(6) & "','" & dr(7) & "','" & dr(8) & "','" & dr(9) & "','" & dr(10) & "','" & dr(11) & "','" & dr(12) & "','" & dr(13) & "','" & dr(14) & "','" & dr(15) & "','" & dr(16) & "','" & dr(17) & "','" & dr(18) & "','" & dr(19) & "','" & dr(20) & "')", con2)
            k = cmd3.ExecuteNonQuery()

        Next


        da1.Update(dt1)
        cmd1.Dispose()
        dt1.Dispose()
        da1.Dispose()

        da2.Update(dt2)
        cmd2.Dispose()
        dt2.Dispose()
        da2.Dispose()

        da3.Update(dt3)
        cmd3.Dispose()
        dt3.Dispose()
        da3.Dispose()

    End Sub
End Class

Reference2

Reference3

Reference4

【问题讨论】:

  • 不要尝试在应用程序的整个生命周期内保留连接。多亏了连接池,每次与数据库通信时创建一个新连接确实会更好。在这种情况下,这可能是每个计时器滴答声。
  • 另外......这看起来很容易受到 sql 注入问题的影响。如果您的整个问题是通过正确使用参数化查询可以避免的数据中的额外单引号,我不会感到惊讶。
  • 还有一点:错误消息对于找出您的问题非常有用。
  • 非常感谢@JoelCoehoorn 的宝贵建议,顺便说一句,没有任何错误消息显示唯一的问题是 con3、con4 数据未复制到新数据库中的相应表
  • 必须抛出一个异常。如果你没有抓住它,服务就会停止。您需要捕获异常并将其记录在 Message 属性中。

标签: sql-server vb.net windows-services ssms


【解决方案1】:

看看这是否有帮助。可能参数化查询是您的全部问题。

Public Class DataCollector

    'Question text said one minute
    Private timer1 As New Timers.Timer(60000)

    Protected Overrides Sub OnStart(ByVal args() As String)
        AddHandler timer1.Elapsed, AddressOf OnTimedEvent
        timer1.Enabled = True
        FileIO.WriteLog("Service has started")
    End Sub

    Protected Overrides Sub OnStop()
        timer1.Enabled = False
        FileIO.WriteLog("Service has stopped")
    End Sub

    Private Sub OnTimedEvent(obj As Object, e As EventArgs)
        ' DEV_Test_Nor_Data Table
        ProcessOneTable("DEV_Test_Nor_Data", 12,
            "Data Source=NORMAC-CTMS\SQLEXPRESS;Database=Normac Data;Integrated Security=true", 
            "SELECT ID, trx_date, work_order, department, work_center, operation_no, operator, total_labor_hours, feet_produced, item_no, posted, labor_feet_produced FROM NOR_LABOR"
        )

        ' DEV_Test_Set_Lbr Table
        ProcessOneTable("DEV_Test_Set_Lbr", 11, 
            "Data Source=201706-SETTER1\SQLEXPRESS;Database=Edge;Integrated Security=true",
            "SELECT ID, trx_date, work_order, department, work_center, operation_no, operator, total_labor_hours, labor_feet_produced, item_no, posted from Setter_Labor"
        )

        ' DEV_Test_Wrp_Lbr Table
        ProcessOneTable("DEV_Test_Wrp_Lbr", 21,
            "Data Source=PRINTER\SQLEXPRESS;Database=Wrapper Data;Integrated Security=true",
            "SELECT ID, trx_date, work_order, Department, work_center, operation_no, operator, total_labor_hrs, job_start, job_end, qty_ordered, qty_produced, item_no, lot_no, default_bin, posted, wrapped, total_shift_hrs, check_emp, machine, operation_complete from wrap_labor"
        )
    End Sub

    Private EdgeConnStr As String = "Data Source=STLEDGSQL01;Database=MES_DEV;Integrated Security=true"

    Private Sub ProcessOneTable(destTableName As String, ParameterCount As Integer, sourceConnectionString AS String, sourceSql As String)
        Dim data As New DataTable()
        Using sourceConn As New SqlConnection(sourceConnectionString), _
              da As New SqlDataAdapter(sourceSql, sourceConn)
            da.Fill(data)
        End Using

        Dim paramList As String = String.Join(",", Enumerable.Range(0, ParameterCount).Select(Function(p) $"@p{p}"))
        ' Assumes first parateter (@p0) is always the ID.
        Dim sql As String = $"INSERT INTO {destTableName} SELECT {paramList} WHERE NOT EXISTS(SELECT ID FROM {destTableName} WHERE ID = @p0)"
        Using cn As New SqlConnection(EdgeConnStr), _
              cmd As New SqlCommand(sql, cn)

            For i As Integer = 0 To ParameterCount - 1
                cmd.Parameters.Add($"@p{i}", SqlDbType.VarChar)
            Next i
        
            cn.Open()
            For Each dr As DataRow In data.Rows
                For i As Integer = 0 to ParameterCount - 1
                    cmd.Parameters(i).Value = dr(i)
                Next i
                cmd.ExecuteNonQuery()
            Next dr
        End Using
    End Sub
End Class

听起来您还需要担心合并数据,但无论如何都要从这个开始;它修复了原始代码中的HUGE GAPING SECURITY ISSUE,并将代码的重要部分隔离到尽可能小的方法大小。这将使重构只是该部分变得更容易,也可以担心哪些 ID 可能已经存在......但我会让你自己先尝试一下(提示:INSERT + SELECT + WHERE NOT EXISTS() all in相同的查询)

【讨论】:

  • 非常感谢您的回答。我已经通过替换我的代码来尝试此代码,但由于某种原因它不起作用。顺便说一句,我想我找到了避免重复 ID 的查询, INSERT INTO {destTableName} SELECT * FROM NOR_LABOR WHERE NOT EXISTS(SELECT ID FROM NOR_LABOR WHERE NOR_LABOR.ID = destTableName.ID) 你也知道制作代码的解决方案工作?非常感谢!
  • 我知道当我说代码不起作用时我应该更具体。对于那个很抱歉。所以windows服务启动和停止没有任何问题。但是现在没有从任何表中复制数据。这就是具体的问题。谢谢
  • 必须抛出一个异常。您想要捕获并记录此异常。
  • 我刚刚检查了多个位置是否有任何线索,同时让 Windows 服务运行。 Windows 事件查看器和 SMSS 日志文件查看器。两者都没有显示任何错误。此外,我目前正在使用 SQL Server Profiler 运行跟踪,但尚未完成。如果有任何例外情况,会通知您。
  • 您必须使用 Try/Catch 并自己记录它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-03-04
  • 2018-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多