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

Posted

技术标签:

【中文标题】无效的操作异常未处理 - 不能一次更新 2 件事【英文标题】:Invalid Operation Exception was unhandled - can't update 2 things at once 【发布时间】:2014-01-12 12:28:54 【问题描述】:

我制作的这个表单允许用户更改他们的用户名、密码和/或安全密码,它连接和更新 XAMPP 数据库。我曾尝试在网上查找,但我对 VB 很陌生,没有任何意义。

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

错误来了:reader = objcommand.ExecuteReader

这是我的代码:

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

公共类 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 个用户。这会影响代码吗? 嗯,当然这是一个改变游戏规则的情况。但是,不要使用适配器来执行这种更改,直接使用 MySqlCommand 抱歉我的无知,但我对 VB/MySQL 很陌生,只使用老师给的笔记。您能否指导我了解我需要在代码中更改的内容? 我已经更新了下面的答案,直接使用命令更改用户名。从那里您可以将相同的技术应用于代码中的其他事件。 【参考方案1】:

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

另外,适配器的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 语句将关闭并销毁连接。

【讨论】:

感谢您的帮助,非常感谢!

以上是关于无效的操作异常未处理 - 不能一次更新 2 件事的主要内容,如果未能解决你的问题,请参考以下文章

Oledb 异常未处理。操作必须使用可更新的查询

无效更新:第 0 节中的无效行数以 NSException 类型的未捕获异常终止

应用程序崩溃:由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“无效更新:第 0 节中的行数无效

无法将车辆信息保存到 firebase [VERBOSE-2:ui_dart_state.cc(186)] 未处理异常:无效参数:“TextEditingController”实例

没有堆栈',原因:'未处理的 JS 异常:无效的正则表达式:无效的组说明符名称

XCode 错误:未捕获的异常“NSInternalInconsistencyException”