【问题标题】:How to distinguish between exceptions如何区分异常
【发布时间】:2016-03-02 17:13:38
【问题描述】:

我正在尝试在 Ruby 中创建一个简单的脚本来访问 MySQL 数据库并根据用户输入运行查询。

如果用户提供错误的登录信息或尝试SELECT FROM 一个不存在的表或列,我希望用户重新输入导致问题,而不必重新输入所有信息。

我希望此代码根据查询的哪一部分引发错误来引发异常:

#!/usr/local/bin/ruby
require "mysql2"
require "watir"
require "csv"

Mysql2::Client.default_query_options.merge!(:as => :array)
mysql = Mysql2::Client.new(:host => "1.2.3.4", :username => "usr", :password => "pass123", :database => "db")

db = "db"

puts "Please enter all `table`.`column` pairs you wish to select from; separated by a comma and space."
tCP = gets.chomp.split(", ")

dynQ = "SELECT "
tCP.each {|pair| dynQ << (db + "." + pair + ", ") }

puts "Please enter the `table` you wish to select from:"
tF = db + "." + gets.chomp

dynQ = dynQ.chop!.chop! + " FROM " + tF + " LIMIT 10;"

report = mysql.query(dynQ)

begin
  report = mysql.query(dynQ)
  report.each {|row| puts row}

  puts "Query Successful!"

rescue Mysql2::Error => e
  puts e.errno
  puts e.error

  puts "Please re-nter all `table`.`column` pairs separated by, ', '."
  tCP = gets.chomp!.split(", ")

  dynQ = "SELECT "
  tCP.each {|pair| dynQ << (db + "." + pair + ", ") }

  tF = db + "."
  puts "Now re-enter the `table` to select `FROM`:"
  tF << gets.chomp!

  dynQ = dynQ.chop!.chop! + " FROM " + tF + " LIMIT 10;"

  retry
end

例如,如果我 SELECT 来自不存在的表或列,我会得到:

/Users/guy/.rvm/gems/ruby-2.3.0/gems/mysql2-0.4.2/lib/mysql2/client.rb:107:in '_query': Table 'db.table_dne' doesn't exist (Mysql2::Error)
  from /Users/guy/.rvm/gems/ruby-2.3.0/gems/mysql2-0.4.2/lib/mysql2/client.rb:107:in 'block in query'
  from /Users/guy/.rvm/gems/ruby-2.3.0/gems/mysql2-0.4.2/lib/mysql2/client.rb:106:in 'handle_interrupt'
  from /Users/guy/.rvm/gems/ruby-2.3.0/gems/mysql2-0.4.2/lib/mysql2/client.rb:106:in 'query'
  from file.rb:23:in '<main>'

但是,如果我从一个不存在的表中进行选择,我会得到完全相同的结果:

/Users/guy/.rvm/gems/ruby-2.3.0/gems/mysql2-0.4.2/lib/mysql2/client.rb:107:in '_query': Unknown column 'db.table_dne' doesn't exist (Mysql2::Error)
  from /Users/guy/.rvm/gems/ruby-2.3.0/gems/mysql2-0.4.2/lib/mysql2/client.rb:107:in 'block in query'
  from /Users/guy/.rvm/gems/ruby-2.3.0/gems/mysql2-0.4.2/lib/mysql2/client.rb:106:in 'handle_interrupt'
  from /Users/guy/.rvm/gems/ruby-2.3.0/gems/mysql2-0.4.2/lib/mysql2/client.rb:106:in 'query'
  from file.rb:23:in '<main>'

理想情况下,我想根据控制台中出现的异常来rescue,并让用户重新输入tCPtF,而不是仅仅给出更一般的异常。

我浏览了MySQL2 documentation 却没有运气。

【问题讨论】:

  • 异常是一个字符串。由于类没有区别,您可以分析异常消息并做任何您想做的事情
  • @nick-roz 这很有帮助;但我只是发现分析e.errno 会更容易。不过,您的评论确实为我指明了正确的方向。
  • 在任何时候都不应允许不受信任的用户输入任何 SQL。这是被黑客入侵的好方法。如果您有点信任用户,那么将信息显示在他们可以从中选择的列表中,这样就无法注入拼写错误和/或临时查询。如果您的界面在命令行上,那么请认真考虑将其移动到 Web 表单中,您可以更好地控制输入,或者编写并运行大量代码来验证他们的输入在提交之前到数据库。一旦它到达数据库,就为时已晚,无法防范恶意 SQL。您可能应该使用 ORM 来帮助保护您的数据库。
  • 在风格上,在 Ruby 中我们不使用 camelCase 作为变量,而是使用 snake_case。它的可读性。

标签: mysql ruby exception mysql2 rescue


【解决方案1】:

让我们分解一下你的尝试:

rescue Mysql2::Error => e
  puts e.errno
  puts e.error
  1. rescue 保持你的脚本运行
  2. Mysql2::Error =&gt; e 取自 Error 类并存储在 e
  3. puts e.errnoputs控制台的错误号
  4. puts e.errorputs控制台的错误描述

因此,以下begin 循环应该适合您:

begin
  report = mysql.query(dynQ)
  report.each {|row| puts row}

  puts "Query Successful!"

rescue Mysql2::Error => e

  if e.errno === 1146
    puts e.error

    tF = db + "."
    puts "Now re-enter the `table` to select `FROM`:"
    tF << gets.chomp!
  elsif e.errno === 1054
    puts e.error

    puts "Please re-nter all `table`.`column` pairs separated by, ', '."
    tCP = gets.chomp!.split(", ")

    dynQ = "SELECT "
    tCP.each {|pair| dynQ << (db + "." + pair + ", ") }
  else
#   puts e.errno
    puts e.error

        puts "Please re-nter all `table`.`column` pairs separated by, ', '."
    tCP = gets.chomp!.split(", ")

    dynQ = "SELECT "
    tCP.each {|pair| dynQ << (db + "." + pair + ", ") }

    tF = db + "."
    puts "Now re-enter the `table` to select `FROM`:"
    tF << gets.chomp!
  end

  dynQ = dynQ.chop!.chop! + " FROM " + tF + " LIMIT 10;"

  retry
end

【讨论】:

    猜你喜欢
    • 2019-09-30
    • 2013-07-30
    • 2014-05-21
    • 2012-02-21
    • 2018-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多