Ruby 开发(十) - 数据库操作(上)

269 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第21天,点击查看活动详情

一、数据持久化

数据库驱动

Ruby 提供了对大部分主流关系型数据库的支持,如 MySQL、SQLite、Oracle 和 PostgreSQL 等,以 MySQL 为例,Ruby 提供了操作 MySQL 数据库的驱动,可以使用 MySQL 模块来操作数据库,也可以使用统一的数据库 DBI 来操作 MySQL,还可以使用更加抽象的 ORM 对象关系映射框架来操作 MySQL。

数据持久化,就是将内存中的数据永久的保存在磁盘中,Ruby 对每一种数据库都提供了一个响应的数据库驱动实现相对应的数据库操作。

Ruby 操作 MySQL 数据库需要安装 dbd-mysql 驱动,有了这个驱动就可以操作数据库了,单数由于每种数据库的驱动不一样,所以 Ruby 还提供了一个 DBI 既 Database Interface,它是对底层的数据库驱动进行的抽象,形成不同的数据库之间的统一的接口。

数据库接口规范 DBI 分为以下三个模块:

  • drh(diriver handle) 驱动句柄,对应 DBD,封装了对数据库的访问,Driver Handler 对于开发者是透明的,只提供给 DBI 使用
  • dbh(database handle) 数据库句柄,封装了对数据库链接的访问,
  • sth(statement handle) 语句或者数据对象句柄,封装了SQL语句执行以后返回值对象

ORM

在面向对象的数据库操作中,使用 DBI 操作数据库费时费力,实际开发中会使用更加快捷的 ORM 框架。

ORM 框架是基于面向对象的一种操作数据库的方式,它抽象了访问数据库的传统方法,使在编程中可以更加方法的实现数据持久化。

ORM、DBI、DBD 以及底层数据库之间的关系

image.png

Rails 框架中提供了 ORM 的实现 - ActiveRecord 插件。

二、Ruby 操作 MySQL

连接 MySQL 数据库

在使用 Ruby 操作 MySQL 之前要先通过 gem install mysql2 安装驱动,如果安装报错很大可能是因为缺少 MySQL 客户端,安装 mysql-client即可。

image.png

Mysql2 中提供了几个关键的类用于连接 MySQL、执行 SQL 语句以及对结果进行处理

Mysql2::Client

该类用于连接 MySQL 数据库以及执行 SQL,实例化 Client 类时可以选填要连接数据库的信息,既数据库的用户名、密码、IP 以及要连接的 database。

image.png

实例化 Client 之后可以通过 Client 对象调用 query 方法来执行 SQL 语句。

Mysql2::Result

Client 对象执行 query 方法返回的结果就是一个 Result 类,该类提供了对执行过的 SQL 语句的结果的处理方法。

image.png

require 'mysql2'

client = Mysql2::Client.new(:host => "localhost",
                            :username => "root", :password => "root",
                            :database => "blog_development", :port => 3306)

sql = "SELECT id, name, title, content FROM articles"

res = client.query(sql)
puts res.class
puts res.fields
puts res.count
puts res.size

puts "迭代器访问结果集"
res.each do |row|
  puts row
  puts row.class
  puts row["id"]
end

client.close

执行上述代码,输出结果如下:

Mysql2::Result
id
name
title
content
3
3
迭代器访问结果集
{"id"=>1, "name"=>"Zulu", "title"=>"Zulu Team", "content"=>"Zulu Team,Do you Copy?"}
Hash
1
{"id"=>2, "name"=>"Yankee", "title"=>"Yankee Team", "content"=>"Yankee Team"}
Hash
2
{"id"=>3, "name"=>"Xray", "title"=>"Xray Team", "content"=>"Xray Team"}
Hash
3

处理查询结果集

使用默认值代替结果集中的 nil 当表中的字段为空时,Ruby 查询结果集中会显示 nil

# 数据库连接代码与上述代码相同,这里省略

sql = "SELECT id, name, title, content FROM articles"

res = client.query(sql)

res.each do |row|
  row["title"] = "标题为空" if row["title"].nil?
  row["content"] = "内容为空" if row["content"].nil?
  puts row
end

执行上述代码,输出结果如下:

{"id"=>1, "name"=>"Zulu", "title"=>"Zulu Team", "content"=>"Zulu Team,Do you Copy?"}
{"id"=>2, "name"=>"Yankee", "title"=>"Yankee Team", "content"=>"Yankee Team"}
{"id"=>3, "name"=>"Xray", "title"=>"Xray Team", "content"=>"Xray Team"}
{"id"=>4, "name"=>"whiskey", "title"=>"标题为空", "content"=>"内容为空"}

特殊字符过滤 在执行 SQL 语句时,可能会向数据库中保存一些特殊符号,比如单引号、双引号、斜杠等,这些字符的存在会导致 SQL 执行报错。

title = "Victor4"3'"
sql = "INSERT INTO articles (title) values ('#{title}')"

client.query(sql)
client.close

执行上述代码,输出结果如下:

/.rvm/gems/ruby-2.7.6/gems/mysql2-0.5.4/lib/mysql2/client.rb:148:in `_query': You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''Victor4"3'')' at line 1 (Mysql2::Error)

这个时候需要用到 client 对象的 escape 方法对字符串进行处理过滤

# 其他代码保持不变
title = client.escape("Victor4"3'")

再次执行上述代码,查询数据库中的记录如下: image.png 包含特殊字符的内容已经被成功插入到数据库中。