2014-12-05 95 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() 
相关问题