当读者打开时,如何在VB中打开execuete查询?

时间:2013-10-04 13:27:29

标签: mysql vb.net

是否有任何可能的方法来执行此操作而不会出现此错误“已经有一个与此Connection关联的打开的DataReader必须先关闭。”我已经尝试使用“dr.close()”,我收到另一个错误,上面写着“读取器关闭时无效的读取尝试”。你能救我吗?

继承我的代码:

Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
    Label2.Text = AllPicker1.Text
    Label3.Text = AllPicker2.Text
    If AllPicker1.Value >= AllPicker2.Value Then
        MsgBox("End Date Must be Greater!")
    Else
        Dim SQLstatement As String = "SELECT * FROM tblStudInfo,tbl_studentLog WHERE tblStudInfo.StudID = tbl_studentLog.StudentNumber AND tbl_studentLog.LoginDate BETWEEN '" & AllPicker1.Text & "' AND '" & AllPicker2.Text & "'"
        OpenData(SQLstatement)
    End If
End Sub

Public Sub OpenData(ByRef SQLstatement As String)
    Dim cmd As MySqlCommand = New MySqlCommand

    With cmd
        .CommandText = SQLstatement
        .CommandType = CommandType.Text
        .Connection = SqlConnection
        dr = .ExecuteReader()
    End With
    While dr.Read
        Dim SQLstatementSave As String = "INSERT INTO tbl_report (RepStudNo,RepName,RepCourse,RepDept,RepLogTime,RepLogdate) VALUES ('" & dr("StudID") & "','" & dr("Name") & "','" & dr("Course") & "','" & dr("Dept") & "','" & dr("LoginTime") & "','" & dr("LoginDate") & "') "
        dr.Close()
        Save(SQLstatementSave)
    End While
    SqlConnection.Close()
    SqlConnection.Dispose()
    SqlConnection.Open()
End Sub

Public Sub Save(ByRef SQLstatementSave As String)
    Dim cmd As MySqlCommand = New MySqlCommand

    With cmd
        .CommandText = SQLstatementSave
        .CommandType = CommandType.Text
        .Connection = SqlConnection
        .ExecuteNonQuery()
    End With

    SqlConnection.Close()
    SqlConnection.Dispose()
    SqlConnection.Open()
End Sub
End Class

3 个答案:

答案 0 :(得分:3)

您似乎只使用一个SqlConnection。对于大多数数据库系统,在读取连接时无法重用连接。您可以将所有数据读入内存/ DataTable并在此之后处理行,或者为插入使用不同的SqlConnection。

使用SqlConnections,读者和命令时,我发现Using Statement非常有助于可视化对象的使用和创建。

答案 1 :(得分:0)

我们可以将其减少为单个查询:

INSERT INTO tbl_report 
      (RepStudNo,RepName,RepCourse,RepDept,RepLogTime,RepLogdate)
   SELECT StudID, Name, Course, Dept, LoginTime, LoginDate
   FROM tblStudInfo
   INNER JOIN tbl_studentLog ON tblStudInfo.StudID = tbl_studentLog.StudentNumber
   WHERE tbl_studentLog.LoginDate BETWEEN @StartDate AND @EndDate

请注意使用完整的INNER JOIN语法。应避免使用旧的TableA,TableB连接语法。另请注意您的日期使用占位符。 这很重要

现在我需要引起注意我看到的几个函数:OpenData()和Save()。

这两个函数从根本上被打破,因为它们会强迫您以一种让您容易受到sql注入黑客攻击的方式构建查询。有一天,有人会将这样的值放入查询中包含的文本框中:

  

'; DROP表tbl_studentLog; -

仔细考虑如果有人在您的AllPicker1.Text中输入了该内容会发生什么。这对日期选择器来说很难做到,但我敢打赌你有其他纯文本字段可以允许这样做。我提议的输入中的第一个字符(单引号)将关闭查询中的字符串文字。第二个字符(分号)将结束单个语句,但sql server 将不会停止执行代码。下一组字符构成一个额外的声明,放弃您的表。最后两个字符注释掉后面的任何内容,以避免由于语法错误而导致sql server拒绝或未提交命令。是的,Sql Server 运行该附加语句,如果这是您放入文本框中的内容。

因此,您编写的方法已被破坏,因为只接受完成的sql字符串作为输入。调用数据库的任何函数必须还包括一个接受查询参数的机制。您最终希望运行更像这样的代码:

Public Sub CreateReport(ByVal StartDate As DateTime, ByVal EndDate As DateTime)
    Dim sql As String = _
         "INSERT INTO tbl_report " & _
            " (RepStudNo,RepName,RepCourse,RepDept,RepLogTime,RepLogdate) " & _
            " SELECT StudID, Name, Course, Dept, LoginTime, LoginDate " & _
            " FROM tblStudInfo " & _
            " INNER JOIN tbl_studentLog ON tblStudInfo.StudID = tbl_studentLog.StudentNumber " & _
            " WHERE tbl_studentLog.LoginDate BETWEEN @StartDate AND @EndDate"

    '.Net is designed such in most cases that you really do want a new SqlConnection for each query
    'I know it's counter-intuitive, but it is the right way to do this
    Using cn As New SqlConnection("Connection string"), _
          cmd As New SqlCommand(sql, cn)

        'Putting your data into the query using parameters like this is safe from injection attacks
        cmd.Parameters.Add("@StartDate", SqlDbType.DateTime).Value = StartDate
        cmd.Parameters.Add("@EndDate", SqlDbType.DateTime).Value = EndDate

        cn.Open()
        cmd.ExecuteNonQuery()
    End Using
End Sub

有一点需要指出的是,乍一看我并没有关闭连接。但是,Using块将确保连接立即关闭... 即使抛出异常。如果出现异常,您现有的代码将挂起连接。

另请注意,在阅读器打开时需要执行单独查询的整个问题这个整齐的侧面步骤...但是如果你真的需要这样做(它是罕见的)答案很简单:使用单独的连接

答案 2 :(得分:0)

而不是:

    Dim SQLstatementSave As String = "INSERT INTO tbl_report
    (RepStudNo,RepName,RepCourse,RepDept,RepLogTime,RepLogdate) 
    VALUES ('" & dr("StudID") & "','" & etc.

尝试在DR()引用上使用.ToString。

    Dim SQLstatementSave As String = "INSERT INTO tbl_report
    (RepStudNo,RepName,RepCourse,RepDept,RepLogTime,RepLogdate) 
    VALUES ('" & dr("StudID").ToString & "','" & etc.