ZetCode

绑定参数

最后修改于 2020 年 7 月 6 日

SQL 语句通常是动态构建的。用户提供一些输入,这些输入被构建到语句中。程序员每次处理来自用户的输入时都必须谨慎。这有一些严重的安全性影响。动态构建 SQL 语句的推荐方法是使用参数绑定。

当我们绑定参数时,我们在语句中创建占位符。占位符是 SQL 语句中的一个特殊标记。它通常是一个问号 ?。稍后,一个参数使用 bind_param、execute、query 等方法绑定到占位符。绑定参数可以保护程序免受 SQL 注入的攻击。它会自动转义一些特殊字符,并允许它们被正确处理。

当语句被预处理并且它们的参数在语句执行之前被绑定时,数据库性能通常会得到提高。在 sqlite3 Ruby 模块中,语句总是被预处理的。即使我们没有调用 prepare 方法并直接调用数据库对象的 execute 方法,该语句也会在后台被 sqlite3 Ruby 模块预处理。

#!/usr/bin/ruby

require 'sqlite3'

begin
    
    db = SQLite3::Database.new "test.db"

    name = "Volkswagen"
    
    stm = db.prepare "SELECT * FROM Cars WHERE Name = ?"
    stm.bind_param 1, name
    rs = stm.execute
    
    row = rs.next    
    puts row.join "\s"
            
rescue SQLite3::Exception => e 
    
    puts "Exception occurred"
    puts e
    
ensure
    stm.close if stm
    db.close if db
end

该示例从 Cars 表中选择一行,用于特定的汽车名称。

name = "Volkswagen"

这是一个可能来自用户的值:例如,来自 HTML 表单。

stm = db.prepare "SELECT * FROM Cars WHERE Name = ?"

问号 ? 是一个值的占位符。它稍后会在脚本中添加。

stm.bind_param 1, name
rs = stm.execute

使用 bind_param 方法,name 变量与语句中的占位符相关联。execute 方法将返回结果集。

$ ./bindparam1.rb 
8 Volkswagen 21600

这是示例的输出。

接下来,我们展示另一种绑定参数的方法。

#!/usr/bin/ruby

require 'sqlite3'

begin
    
    db = SQLite3::Database.new "test.db"

    id = 4
    
    stm = db.prepare "SELECT * FROM Cars WHERE Id = :id"
    rs = stm.execute id
    
    row = rs.next    
    puts row.join "\s"
            
rescue SQLite3::Exception => e 
    
    puts "Exception occurred"
    puts e
    
ensure
    stm.close if stm
    db.close if db
end

我们从 Cars 表中选择一行,用于特定的 Id。

stm = db.prepare "SELECT * FROM Cars WHERE Id = :id"

之前我们已经看到了问号作为占位符。SQLite Ruby 也支持命名占位符。

rs = stm.execute id

参数在 execute 方法中绑定。

我们提供了另一种绑定参数的方法。

#!/usr/bin/ruby

require 'sqlite3'

begin
    
    db = SQLite3::Database.new "test.db"

    id = 3
    row = db.get_first_row "SELECT * FROM Cars WHERE Id = ?", id       
    puts row.join "\s"
            
rescue SQLite3::Exception => e 
    
    puts "Exception occurred"
    puts e
    
ensure
    db.close if db
end

这一次,所有事情——预处理语句、绑定参数和执行语句——都使用一个方法完成。

row = db.get_first_row "SELECT * FROM Cars WHERE Id = ?", id    

get_first_row 是一个方便的方法,它在一个步骤中完成三件事。

在我们的最后一个例子中,我们将在一个语句中绑定多个参数。

#!/usr/bin/ruby

require 'sqlite3'

begin
    
    db = SQLite3::Database.new ":memory:"
   
    stm = db.prepare "SELECT 2 + ? + 6 + ? + ?"
    stm.bind_params 3, 4, 6
    rs = stm.execute
    
    row = rs.next    
    puts row
            
rescue SQLite3::Exception => e 
    
    puts "Exception occurred"
    puts e
    
ensure
    stm.close if stm
    db.close if db
end

在这个例子中,我们在 SQL 语句中有更多的占位符。

stm = db.prepare "SELECT 2 + ? + 6 + ? + ?"

在 SELECT 语句中有三个占位符。

stm.bind_params 3, 4, 6

我们使用 bind_params 方法绑定三个值。

$ ./bindparams.rb
21

这是 bindparams.rb 程序的输出。

在 SQLite Ruby 教程的这一部分中,我们讨论了绑定参数。