打开与此Connection关联的DataReader,必须先关闭

时间:2014-12-05 09:50:06

标签: mysql vb.net

我正在尝试制作POS(销售点)应用程序,但我收到了此错误。 "已经有一个与此Connection关联的开放DataReader,必须先关闭。"

以下是我的代码:

使用MySQL的数据库

If txt_notr.Text = "" Or txt_kodep.Text = "" Or txt_item.Text = "" Or txt_gt.Text = "" Or txt_bayar.Text = "" Then
        MsgBox("Data belum lengkap...!!!")
        Exit Sub
    Else
        'Simpan ke tabel penjualan
        db.Close()
        db.Open()
        Call Koneksi()
        Dim simpan1 As String = "Insert Into tb_penjualan values('" & txt_notr.Text & "','" & Format(Now, "yyyy-MM-dd") & "','" & txt_kodep.Text & "','" & txt_item.Text & "','" & txt_gt.Text & "','" & txt_bayar.Text & "')"
        cmd = New MySqlCommand(simpan1, db)
        cmd.ExecuteNonQuery()
        db.Close()
        db.Open()
        'Simpan ke tabel detail penjualan
        For baris As Integer = 0 To DGV.Rows.Count - 2
            Dim simpandet As String = "Insert into tb_detjual values('" & txt_notr.Text & "','" & DGV.Rows(baris).Cells(0).Value & "','" & DGV.Rows(baris).Cells(3).Value & "','" & DGV.Rows(baris).Cells(4).Value & "','" & DGV.Rows(baris).Cells(5).Value & "')"
            cmd = New MySqlCommand(simpandet, db)
            cmd.ExecuteNonQuery()
            db.Close()
            db.Open()
            cmd = New MySqlCommand("Select * from tb_stok where id_obat = '" & DGV.Rows(baris).Cells(0).Value & "'", db)
            dr = cmd.ExecuteReader
            dr.Read()
            If dr.HasRows Then
                Dim kurangstok As String = "Update tb_stok set stok = '" & dr.Item("stok") - DGV.Rows(baris).Cells(4).Value & "' where id_obat = '" & DGV.Rows(baris).Cells(0).Value & "'"
                cmd = New MySqlCommand(kurangstok, db)
                cmd.ExecuteNonQuery()    'The Error shows here...
            End If
        Next
        Call hapustemp()
        Call bersih()
        Call notrans()
    End If
    db.Close()

1 个答案:

答案 0 :(得分:0)

这是违反直觉的,但是ADO.Net提供商使用了一个名为Connection Pooling的功能,这样在大多数情况下,为了对数据库进行单独调用,您最好创建一个新的连接对象,而不是尝试在类中保留单个数据库连接以重复使用。下面的代码显示了重用连接对象的正确方法:为方法创建新连接,并在方法持续时间内使用它。但是,当方法完成时,请收集连接。

我注意到你也有一些严重不安全的代码。在对数据库进行更多工作之前,您应该阅读Sql Injection。这是一个巨大问题。如果你不了解数据库代码,并且没有正确的方法来避免这个问题,你就不应该专业地编写数据库代码。

最后,代码使用了一些源自旧版VBScript / VB6的约定,不再合适。

下面的代码解决了所有这些问题,并且通过避免需要从数据库为每个gridview行运行SELECT来快速

If String.IsNullOrWhiteSpace(txt_notr.Text) OrElse String.IsNullOrWhiteSpace(txt_kodep.Text) OrElse String.IsNullOrWhiteSpace(txt_item.Text) OrElse String.IsNullOrWhiteSpace(txt_gt.Text) OrElse String.IsNullOrWhiteSpace(txt_bayar.Text_ Then
    MsgBox("Data belum lengkap...!!!")
    Exit Sub
End If

'No need for an "Else". The "Exit Sub" takes care of it.

'Simpan ke tabel penjualan
'Note that I was able to let the database set the time stamp
Dim sql As String = "Insert Into tb_penjualan values(@notr, current_timestamp, @kodep, @item, @gt, @bayar);" 

'The "Using" keyword will guarantee the connection closes, even if an exception is thrown
Using cn As New MySqlConnection(" connection string here "), _
      cmd As New MySqlCommand(sql, cn)

    'Use parameter placeholders rather than string concatenation. This avoids a SERIOUS security issue. 
    ' I have to guess parameter types/lengths, but you should use actual types/lengths that match your database
    cmd.Parameters.Add("@notr", MySqlDbType.Int32).Value = CInt(txt_notr.Text)
    cmd.Parameters.Add("@kodep", MySqlDbType.VarChar, 20).Value = txt_kodep.Text
    cmd.Parameters.Add("@item", MySqlDbType.VarString, 1000).Value = txt_item.Text
    cmd.Parameters.Add("@gt", MySqlDbType.VarChar, 50).Value = txt_gt.Text
    cmd.Parameters.Add("@bayar", MySqlDbType.VarChar, 50).Value = txt_bayar.Text

    cn.Open()
    cmd.ExecuteNonQuery()

    'Two sql statements in a single call to the database.
    'This is MUCH better than the Insert/Select/Update process you were using
    sql = "INSERT INTO tb_detjual VALUES (@notr, @c0, @c3, @c4, @c5);" & _
      "UPDATE tb_stok SET stok = stok - @c4 WHERE id_obat = @c0;"
    'See how I was able to re-use the same parameters in the query.

    cmd.Parameters.Clear()
    cmd.CommandText = sql
    cmd.Parameters.Add("@notr", MySqlDbType.Int32).Value = CInt(txt_notr.Text)
    cmd.Parameters.Add("@c0", MySqlDbType.VarChar, 50)
    cmd.Parameters.Add("@c3", MySqlDbType.VarChar, 50)
    cmd.Parameters.Add("@c4", MySqlDbType.VarChar, 50)
    cmd.Parameters.Add("@c5", MySqlDbType.VarChar, 50)

   'Simpan ke tabel detail penjualan
    For baris As Integer = 0 To DGV.Rows.Count - 2
        'I'm able to re-use the same parameters for each loop
        cmd.Parameters("@c0").Value = DGV.Rows(baris).Cells(0).Value
        cmd.Parameters("@c3").Value = DGV.Rows(baris).Cells(3).Value
        cmd.Parameters("@c4").Value = DGV.Rows(baris).Cells(4).Value
        cmd.Parameters("@c5").Value = DGV.Rows(baris).Cells(5).Value

        cmd.ExecuteNonQuery()
    Next

End Using

hapustemp()
bersih()
notrans()