2014-12-05 89 views
0

我正在嘗試創建POS(銷售點)應用程序,並且出現此錯誤。 「已經有一個開放的DataReader與這個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

你爲什麼叫db.Close; ,緊接着重新開放它後?我還想指出,這似乎是開放的sql注入(讀取使用sqlParameters代替) – jbutler483 2014-12-05 09:55:32

+0

錯誤消息是明確的。您正嘗試使用已被打開的DataReader使用的連接。您必須先關閉數據讀取器(dr),然後才能在另一個查詢中使用該連接。順便說一句,您的查詢可以廣泛應用於Sql Injection攻擊。您應該使用參數化查詢。 – 2014-12-05 14:17:20

+0

感謝球員的評論,無論如何,我已經刪除了「db.close」像jbutler483建議,但我真的不知道我應該把「dr.close」 – 2014-12-05 23:40:55

回答

0

這是違反直覺的,但ADO.Net供應商使用一個功能叫做連接池,這樣,你真的是最好創建一個新的

數據庫連接對象在大多數情況下用於單獨調用數據庫,而不是試圖在類中保留單個數據庫連接以重用。下面的代碼顯示了重新使用連接對象的正確方法:爲該方法創建一個新連接,並在該方法的持續時間內使用它。但是,然後在方法完成時收集連接。

我注意到你也有一些嚴重不安全的代碼。在進行數據庫的更多工作之前,您應該閱讀Sql Injection。這是一個巨大的問題。如果你不知道這些,你就不應該專業地編寫數據庫代碼,並且避免這個問題的正確方法。

最後,代碼使用了一些源於舊版VBScript/VB6的約定,不再合適。

下面的代碼解決了所有這些問題,而應該是通過避免需要從數據庫中運行SELECT每個gridview的行更快:

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() 
相關問題