我正在尝试制作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()
答案 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()