无效操作异常未处理 - 无法一次更新2件事

时间:2013-12-24 09:03:18

标签: mysql vb.net xampp

我做的这个表单允许用户更改他们的用户名,密码和/或安全密码,并在XAMPP数据库上连接和更新。我试过在网上看,但我对VB很新,没有什么比这更有意义了。

问题是我可以更改其中任何一个,但是如果我在更改之后尝试更改另一个,我会收到错误: InvalidOperationException未处理 连接必须有效并且打开

错误来自: reader = objcommand.ExecuteReader

这是我的代码:

`导入MySql.Data 导入MySql.Data.MySqlClient

Public Class frmAccountSettings

Private Sub frmAccountSettings_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    objconnection.Open()
    objdataadapter.SelectCommand = New MySqlCommand
    objdataadapter.SelectCommand.Connection = objconnection
    objdataadapter.SelectCommand.CommandText = "Select * FROM Login"
End Sub

Private Sub btnBack_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBack.Click
    frmMainMenu.Show()
    Me.Hide()
End Sub

Private Sub btnChangeUsername_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnChangeUsername.Click
    Dim password1, newusername As String
    password1 = InputBox("What is the current password?")
    sqlstring = "SELECT password FROM Login WHERE Password = '" &
password1 & "'"
    objcommand = New MySqlCommand(sqlstring, objconnection)
    reader = objcommand.ExecuteReader

    If reader.Read Then
        reader.Close()
        newusername = InputBox("Enter a new username")
        sqlstring = "UPDATE `Login` SET `username` =  '" & newusername &
"'  WHERE `Login`.`password` = '" & password1 & "'"
        objdataadapter.SelectCommand.CommandText = sqlstring
        objdataadapter.SelectCommand.CommandType = CommandType.Text

        objdataset = New DataSet
        objdataadapter.Fill(objdataset, "Login")

        objconnection.Close()

    Else
        MsgBox("Incorrect Username. Please make sure your credentials are correct and try again.", MsgBoxStyle.Critical, "Authentication Failed")
        reader.Close()
    End If
End Sub

Private Sub btnChangePassword_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnChangePassword.Click
    Dim oldpassword, newpassword1 As String
    oldpassword = InputBox("What is the current password?")
    sqlstring = "SELECT password FROM Login WHERE Password = '" &
oldpassword & "'"
    objcommand = New MySqlCommand(sqlstring, objconnection)
    reader = objcommand.ExecuteReader

    If reader.Read Then
        reader.Close()
        newpassword1 = InputBox("Enter a new password")
        sqlstring = "UPDATE `Login` SET `password` =  '" & newpassword1 &
"'  WHERE `Login`.`password` = '" & oldpassword & "'"
        objdataadapter.SelectCommand.CommandText = sqlstring
        objdataadapter.SelectCommand.CommandType = CommandType.Text

        objdataset = New DataSet
        objdataadapter.Fill(objdataset, "Login")

        objconnection.Close()

    Else
        MsgBox("Incorrect Password. Please make sure your credentials are correct and try again.", MsgBoxStyle.Critical, "Authentication Failed")
        reader.Close()
    End If
End Sub

Private Sub btnChangeSecurity_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnChangeSecurity.Click
    Dim password2, newsecurity As String
    password2 = InputBox("What is the current password?")
    sqlstring = "SELECT password FROM Login WHERE Password = '" &
password2 & "'"
    objcommand = New MySqlCommand(sqlstring, objconnection)
    reader = objcommand.ExecuteReader

    If reader.Read Then
        reader.Close()
        newsecurity = InputBox("Enter a new security passphrase")
        sqlstring = "UPDATE `Login` SET `security` =  '" & newsecurity &
"'  WHERE `Login`.`password` = '" & password2 & "'"
        objdataadapter.SelectCommand.CommandText = sqlstring
        objdataadapter.SelectCommand.CommandType = CommandType.Text

        objdataset = New DataSet
        objdataadapter.Fill(objdataset, "Login")

        objconnection.Close()

    Else
        MsgBox("Incorrect Password. Please make sure your credentials are correct and try again.", MsgBoxStyle.Critical, "Authentication Failed")
        reader.Close()
    End If
End Sub

结束课程 `

1 个答案:

答案 0 :(得分:0)

我认为您的代码中存在一些错误。最严重的是逻辑缺陷 您无法确定两个用户是否总是选择不同的密码。您需要确保数据条Loginprimary key字段中有username,并在查询中使用该字段来唯一标识要更改的记录。此外,更改用作主键的用户名并非易事。您需要检查其他用户是否尚未使用新用户名。如果您的应用程序在共享环境中使用,您还需要考虑并发更改(两个用户决定将其用户名更改为相同的新名称)

此外,适配器的SelectCommand不是执行数据库更新的适当方法。但是,根本不需要使用适配器来执行这些操作,您可以使用MySqlCommand执行所有操作。

将密码以明文形式存储在数据表中还有另一个安全问题。您永远不应该这样做,而是应该在将密码存储到表中之前对其使用散列函数。

但是,限制我对当前问题的回答并排除并发问题,我会以这种方式更改您的代码(当然username 应该是主键)...

Dim password1, newusername, oldusername As String
oldusername = InputBox("Type the current username")
password1 = InputBox("What is the current password?")
newusername = InputBox("Enter a new username")

' identify the current user ... '
sqlstring = "SELECT COUNT(*) FROM `Login` WHERE `username` =  @uname AND `password` = @pwd"
objcommand = New MySqlCommand(sqlstring, objconnection)
objcommand.Parameters.AddWithValue("@uname", oldusername)
objcommand.Parameters.AddWithValue("@pwd", password1)
Dim result  = objcommand.ExecuteScalar
if result IsNot Nothing AndAlso Convert.ToInt32(result) > 0 Then

    ' we have good credentials, but the new user name should be unique '
    sqlstring = "SELECT COUNT(*) FROM `Login` WHERE `username` =  @uname"
    objcommand = New MySqlCommand(sqlstring, objconnection)
    objcommand.Parameters.AddWithValue("@uname", newusername)
    Dim result  = objcommand.ExecuteScalar
    if result Is Nothing OrElse Convert.ToInt32(result) = 0 Then
        ' we could change the username of the current user '
        sqlstring = "UPDATE `Login` SET `username` =  @newame WHERE `username` = @oldname"
        objcommand = New MySqlCommand(sqlstring, objconnection)
        objcommand.Parameters.AddWithValue("@newame", newusername)
        objcommand.Parameters.AddWithValue("@oldname", oldusername)
        objcommand.ExecuteNonQuery()
    else
        MessageBox.Show("Username already taken, choose a different one")
    End If
Else
    MessageBox.Show("Invalid credentials given")
End If

通过这种方式,您可以使用用户和密码的组合来唯一标识数据库中的用户,并更改所涉及的确切记录。

当您想要更改密码字段时,请求用户名和密码,只有在用户名和密码匹配时才更新字段。

编辑根据您上面的评论,如果数据库中只有一个用户,那么您可以直接执行更改而无需任何复杂的检查。 (但这确实是一个不能被认为普遍存在的情况)

    sqlstring = "UPDATE `Login` SET `username` =  @newame WHERE `password` = @pwd"
    objcommand = New MySqlCommand(sqlstring, objconnection)
    objcommand.Parameters.AddWithValue("@newame", newusername)
    objcommand.Parameters.AddWithValue("@pwd", password1)
    objcommand.ExecuteNonQuery()

另一个问题是连接对象。它是一个在Form_Load事件中打开的全局对象,然后一直挂在你的代码上,但在某些地方你关闭它,当你尝试执行另一个数据库操作时,你忘了重新打开。这是一个很好的做法,没有全局用于连接的对象,而是在需要时构建一个,使用它然后将其销毁

例如

Private Sub btnChangeSecurity_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnChangeSecurity.Click
    Using objconnection = new MySqlConnection(....connectionstring goes here ....)
        objconnection.Open()
        Dim sqlstring = "UPDATE `Login` SET `username` =  @newame WHERE `password` = @pwd"
        objcommand = New MySqlCommand(sqlstring, objconnection)
        objcommand.Parameters.AddWithValue("@newame", newusername)
        objcommand.Parameters.AddWithValue("@pwd", password1)
        objcommand.ExecuteNonQuery()
    End Using
End Sub

如果将数据库访问代码放在上面的using语句中,则创建连接对象,打开它,使用它,完成后,End Using语句将关闭并销毁连接。