Ruby 数据库访问
Ruby 数据库访问
Section titled “Ruby 数据库访问”本教程将指导您如何使用 Ruby 访问数据库。虽然存在 Ruby/DBI 等较旧的库,但现代 Ruby 应用程序通常使用针对每个数据库系统的特定适配器 gem(例如,用于 PostgreSQL 的 pg、用于 MySQL 的 mysql2、用于 SQLite 的 sqlite3)。这些 gem 提供了数据库的直接接口。
对于更复杂的应用程序,通常使用对象关系映射(ORM),例如 ActiveRecord(Ruby on Rails 的一部分)或 Sequel。ORM 在 SQL 之上提供更高级别的抽象。本教程将重点介绍如何使用直接适配器 gem sqlite3,因为其简单易于设置(无需独立的数据库服务器)。
支持的数据库 (通过 Gems):
- SQLite (通过
sqlite3gem) - PostgreSQL (通过
pggem) - MySQL/MariaDB (通过
mysql2gem) - Oracle (通过
ruby-oci8gem) - SQL Server (通过
tiny_tdsgem) - 以及通过特定 gem 支持许多其他数据库。
使用适配器 Gem 的架构
Section titled “使用适配器 Gem 的架构”使用适配器 gem 时,您的 Ruby 脚本通过 gem 的 API 直接与数据库通信。gem 负责处理特定数据库的低级通信协议。
Ruby 应用程序 -> 适配器 Gem (例如 sqlite3) -> 数据库 (例如 SQLite 文件)
要遵循本教程,您需要安装 Ruby 和 sqlite3 gem。您可能还需要在系统上安装 SQLite3 开发库,以便 gem 能够编译。
使用命令行安装 gem:
gem install sqlite3数据库连接:
Section titled “数据库连接:”首先,require (引入) gem,然后创建数据库连接。对于 SQLite,这涉及创建或打开数据库文件。
#!/usr/bin/env ruby# frozen_string_literal: true
require 'sqlite3'
begin # 打开数据库。如果 'test.db' 不存在,将会创建它。 db = SQLite3::Database.new 'test.db' db.results_as_hash = true # 将结果作为哈希而不是数组返回
puts "Opened database successfully"
# 示例: 获取 SQLite 版本 version = db.get_first_value 'SELECT SQLITE_VERSION()' puts "SQLite version: #{version}"
rescue SQLite3::Exception => e puts "Database error: #{e.message}" puts "Exception class: #{e.class}"ensure # 如果数据库连接已打开,始终关闭它 db.close if dbend如果连接建立成功,将返回一个 SQLite3::Database 对象。ensure 块确保调用 db.close,从而释放资源。
execute 方法用于运行不返回行的 SQL 语句,例如 CREATE TABLE。
#!/usr/bin/env ruby# frozen_string_literal: true
require 'sqlite3'
begin db = SQLite3::Database.new 'company.db' db.execute "DROP TABLE IF EXISTS employees" db.execute <<~SQL CREATE TABLE employees ( id INTEGER PRIMARY KEY AUTOINCREMENT, first_name TEXT NOT NULL, last_name TEXT, age INTEGER, position TEXT, salary REAL ); SQL puts "表 'employees' 已成功创建。"rescue SQLite3::Exception => e puts "创建表时出错: #{e}"ensure db.close if dbendINSERT 操作:
Section titled “INSERT 操作:”要插入数据,请使用 execute 方法和 INSERT 语句。至关重要的是要使用参数化查询(占位符,例如 ?)来防止 SQL 注入漏洞。
#!/usr/bin/env ruby# frozen_string_literal: true
require 'sqlite3'
begin db = SQLite3::Database.new 'company.db' # 如果表不存在则创建 (假定之前的脚本已运行或在此处添加创建代码) # db.execute "CREATE TABLE IF NOT EXISTS employees (...);"
# 使用占位符插入单条记录 db.execute("INSERT INTO employees (first_name, last_name, age, position, salary) VALUES (?, ?, ?, ?, ?)", 'John', 'Doe', 30, 'Developer', 60000.0)
# 插入多条记录 employees_data = [ ['Jane', 'Smith', 28, 'Designer', 55000.0], ['Mike', 'Johnson', 35, 'Manager', 75000.0] ]
employees_data.each do |emp| db.execute("INSERT INTO employees (first_name, last_name, age, position, salary) VALUES (?, ?, ?, ?, ?)", emp[0], emp[1], emp[2], emp[3], emp[4]) end
puts "已插入 #{db.changes} 条记录。" # 注意: db.changes 返回最近执行的 DML 语句 (INSERT, UPDATE, DELETE) 影响的行数 # 对于循环中插入的总行数,您需要对它们进行求和或单独计数。
puts "记录已成功创建"
rescue SQLite3::Exception => e puts "插入记录时出错: #{e}"ensure db.close if dbendREAD 操作:
Section titled “READ 操作:”要获取数据,请使用 execute 方法和 SELECT 语句。如果设置了 db.results_as_hash = true,则每行是一个哈希。否则,它是一个数组。
#!/usr/bin/env ruby# frozen_string_literal: true
require 'sqlite3'
begin db = SQLite3::Database.new 'company.db' db.results_as_hash = true
puts "薪水高于 58000 的员工:" # 使用占位符作为查询参数 min_salary = 58000.0 db.execute("SELECT id, first_name, last_name, position, salary FROM employees WHERE salary > ?", min_salary) do |row| puts "ID: #{row['id']}, Name: #{row['first_name']} #{row['last_name']}, Position: #{row['position']}, Salary: #{row['salary']}" end
# 获取单个值 count = db.get_first_value "SELECT COUNT(*) FROM employees" puts "\n总员工数: #{count}"
rescue SQLite3::Exception => e puts "读取记录时出错: #{e}"ensure db.close if dbendUPDATE 操作:
Section titled “UPDATE 操作:”使用 execute 方法和 UPDATE 语句以及占位符。
#!/usr/bin/env ruby# frozen_string_literal: true
require 'sqlite3'
begin db = SQLite3::Database.new 'company.db'
# 给 John Doe 加薪 new_salary = 65000.0 target_id = 1 # 假定 John Doe 的 ID 是 1 db.execute("UPDATE employees SET salary = ? WHERE id = ?", new_salary, target_id)
puts "已更新 #{db.changes} 条记录。"rescue SQLite3::Exception => e puts "更新记录时出错: #{e}"ensure db.close if dbendDELETE 操作:
Section titled “DELETE 操作:”使用 execute 方法和 DELETE 语句以及占位符。
#!/usr/bin/env ruby# frozen_string_literal: true
require 'sqlite3'
begin db = SQLite3::Database.new 'company.db'
# 按 ID 删除员工 (例如,ID 为 2 的员工) employee_id_to_delete = 2 db.execute("DELETE FROM employees WHERE id = ?", employee_id_to_delete)
puts "已删除 #{db.changes} 条记录。"rescue SQLite3::Exception => e puts "删除记录时出错: #{e}"ensure db.close if dbend事务确保一系列数据库操作要么全部成功,要么全部失败,从而维护数据一致性。这些属性包括原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)(ACID)。
sqlite3 gem 提供了一个 transaction 块方法,这是处理事务的推荐方式。它在成功时自动处理 COMMIT,在发生异常时自动处理 ROLLBACK。
#!/usr/bin/env ruby# frozen_string_literal: true
require 'sqlite3'
db = SQLite3::Database.new 'company.db'
begin # 示例: 在部门之间转移虚构的“项目预算” (概念性示例) # 假定存在一个 'departments' 表,包含 'name' 和 'budget' 列 # db.execute "CREATE TABLE IF NOT EXISTS departments (name TEXT, budget REAL);" # db.execute "INSERT INTO departments VALUES ('Sales', 10000);" # db.execute "INSERT INTO departments VALUES ('Marketing', 5000);"
db.transaction do # 此块在事务中执行 puts "正在开始事务..." # 减少销售预算 db.execute("UPDATE employees SET salary = salary - 1000 WHERE first_name = ?", 'John') puts "已减少 John 的薪水。"
# 增加市场预算 (此处模拟错误) # 如果此行引发错误,整个事务将被回滚。 # db.execute("UPDATE employees SET salary = salary + 1000 WHERE non_existent_column = ?", 'Jane') # 有意制造的错误 db.execute("UPDATE employees SET salary = salary + 1000 WHERE first_name = ?", 'Jane') puts "已增加 Jane 的薪水。"
puts "事务操作已在块内完成。" # 如果块在没有异常的情况下完成,则会自动进行 COMMIT。 end puts "事务已成功提交。"
rescue SQLite3::Exception => e puts "事务失败并已回滚: #{e.message}"rescue StandardError => e puts "事务期间发生意外错误: #{e.message}"ensure db.close if dbend您也可以使用 db.execute 'BEGIN TRANSACTION'、db.execute 'COMMIT' 和 db.execute 'ROLLBACK' 手动管理事务,但块形式更安全,更符合 Ruby 习惯用法。
本教程简要介绍了使用 sqlite3 gem 的基本数据库操作。对于大型应用程序,可以进一步探索:
- 其他数据库系统及其特定的 gem(例如用于 PostgreSQL 的
pg、用于 MySQL 的mysql2)。 - 像 ActiveRecord 或 Sequel 这样的 ORM,提供更高级的、面向对象的方式与数据库交互。
- 高级主题,如连接池、数据库迁移和复杂的查询构建。