Ruby / DBI教程

本章将教您如何使用Ruby访问数据库. Ruby DBI 模块为类似于Perl DBI模块的Ruby脚本提供了一个独立于数据库的接口.

DBI代表Ruby的数据库独立接口,表示DBI在Ruby代码和底层数据库之间提供了一个抽象层,允许您非常轻松地切换数据库实现.它定义了一组方法,变量和约定,它们提供了一致的数据库接口,与所使用的实际数据库无关.

DBI可以与以下相关联;

  • ADO(ActiveX数据对象)

  • DB2

  • Frontbase

  • mSQL

  • MySQL

  • ODBC

  • Oracle

  • OCI8(Oracle)

  • PostgreSQL

  • 代理/服务器

  • SQLite

  • SQLRelay

DBI应用程序的体系结构

DBI独立于后端可用的任何数据库.无论您使用的是Oracle,MySQL还是Informix等,都可以使用DBI.从以下架构图中可以清楚地看到这一点.

Ruby DBI Architecture

Ruby DBI的一般架构使用两层 :

  • 数据库接口(DBI)层.该层与数据库无关,并提供一组常用访问方法,无论您与之通信的数据库服务器类型如何,它们都以相同的方式使用.

  • 数据库驱动程序(DBD)层.该层依赖于数据库;不同的驱动程序提供访问不同数据库引擎有一个用于MySQL的驱动程序,另一个用于PostgreSQL,另一个用于InterBase,另一个用于Oracle,依此类推.每个驱动程序解释来自DBI层的请求,并将它们映射到适合给定类型的数据库服务器的请求.

先决条件

如果你想编写Ruby脚本来访问MySQL数据库,你需要安装Ruby MySQL模块.

这个模块充当DBD,如解释以上,可以从 https://www.tmtm.org/en/mysql/ruby/

获取并安装Ruby/DBI

您可以从以下位置下载并安装Ruby DBI模块 :

https://imgur.com/NFEuWe4/embed

在开始此安装之前,请确保您具有root权限.现在,按照下面给出的步骤&减去;

步骤1

$ tar zxf dbi-0.2.0.tar.gz

步骤2

进入分发目录 dbi-0.2.0  setup.rb 脚本配置它.最常见的配置命令如下所示,config参数后面没有参数.此命令配置分发以默认安装所有驱动程序.

$ ruby setup.rb config

更具体地说,提供一个--with选项,列出您要使用的分发的特定部分.例如,要仅配置主DBI模块和MySQL DBD级驱动程序,请发出以下命令 :

$ ruby setup.rb config --with = dbi,dbd_mysql

步骤3

最后一步是构建驱动程序并使用它来安装它以下命令 :

$ ruby setup.rb setup
$ ruby setup.rb install

数据库连接

假设我们要使用MySQL数据库,在连接到数据库之前请确保以下和减去;

  • 您已经创建了一个数据库TESTDB.

  • 您已经创建了EMPLOYEE在TESTDB中.

  • 此表包含字段FIRST_NAME,LAST_NAME,AGE,SEX和INCOME.

  • 用户ID"testuser"和密码"test123"设置为访问TESTDB.

  • Ruby Module DBI已正确安装在您的机器上e.

  • 您已通过MySQL教程了解MySQL基础知识.

以下是连接MySQL数据库"TESTDB"的示例

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   # get server version string and display it
   row = dbh.select_one("SELECT VERSION()")
   puts "Server version: " + row[0]
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

运行此脚本时,它会产生以下结果: Linux机器.

Server version: 5.0.45

如果是与数据源建立连接,然后返回数据库句柄并保存到 dbh 以供进一步使用,否则 dbh 设置为nil值并且 e.err e :: errstr 分别返回错误代码和错误字符串.

最后,在出来之前,确保关闭数据库连接并且资源发布.

INSERT操作

当你想在数据库表中创建记录时,需要INSERT操作.

建立数据库连接后,我们就可以创建表或记录了数据库表使用执行方法或准备执行方法.

使用do语句

可以通过调用 do 数据库句柄方法来发出不返回行的语句.此方法接受一个语句字符串参数,并返回受该语句影响的行数.

dbh.do("DROP TABLE IF EXISTS EMPLOYEE")
dbh.do("CREATE TABLE EMPLOYEE (
   FIRST_NAME  CHAR(20) NOT NULL,
   LAST_NAME  CHAR(20),
   AGE INT,  
   SEX CHAR(1),
   INCOME FLOAT )" );

同样,您可以执行SQL INSERT 语句在EMPLOYEE表中创建记录.

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   dbh.do( "INSERT INTO EMPLOYEE(FIRST_NAME, LAST_NAME, AGE, SEX, INCOME)
      VALUES ('Mac', 'Mohan', 20, 'M', 2000)" )
   puts "Record has been created"
   dbh.commit
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
   dbh.rollback
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

使用prepare和execute

您可以使用准备执行 DBI类的方法,通过Ruby代码执行SQL语句.

记录创建采用以下步骤 :

  • 使用INSERT语句准备SQL语句.这将使用准备方法完成.

  • 执行SQL查询以从数据库中选择所有结果.这将使用执行方法完成.

  • 释放语句句柄.这将使用完成 API

  • 完成.

  • 如果一切顺利,那么提交此操作,否则你可以回滚完整的交易.

以下是使用这两种方法的语法 :

sth = dbh.prepare(statement)
sth.execute
   ... zero or more SQL operations ...
sth.finish

这两种方法可用于将 bind 值传递给SQL语句.可能存在未提前输入要输入的值的情况.在这种情况下,使用绑定值.使用问号()代替实际值,然后通过execute()API传递实际值.

以下是创建两个的示例EMPLOYEE表中的记录 :

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   sth = dbh.prepare( "INSERT INTO EMPLOYEE(FIRST_NAME, LAST_NAME, AGE, SEX, INCOME)
      VALUES (?, ?, ?, ?, ?)" )
   sth.execute('John', 'Poul', 25, 'M', 2300)
   sth.execute('Zara', 'Ali', 17, 'F', 1000)
   sth.finish
   dbh.commit
   puts "Record has been created"
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
   dbh.rollback
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

如果有多个INSERT一次,然后先准备一个语句然后在循环中多次执行它比每次循环调用都更有效.

READ操作

READ对任何数据库的操作意味着从数据库中获取一些有用的信息.

建立数据库连接后,我们就可以对该数据库进行查询了.我们可以使用执行方法或准备执行方法从数据库表中获取值.

记录提取需要以下步骤 :

  • 根据所需条件准备SQL查询.这将使用准备方法完成.

  • 执行SQL查询以从数据库中选择所有结果.这将使用执行方法完成.

  • 逐个获取所有结果并打印这些结果.这将使用 fetch 方法完成.

  • 释放语句句柄.这将使用完成方法完成.

以下是查询EMPLOYEE所有记录的过程工资超过1000的表.

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   sth = dbh.prepare("SELECT * FROM EMPLOYEE WHERE INCOME > ?")
   sth.execute(1000)

   sth.fetch do |row|
   printf "First Name: %s, Last Name : %s\n", row[0], row[1]
   printf "Age: %d, Sex : %s\n", row[2], row[3]
   printf "Salary :%d \n\n", row[4]
end
   sth.finish
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

这将产生以下结果 :

First Name: Mac, Last Name : Mohan
Age: 20, Sex : M
Salary :2000

First Name: John, Last Name : Poul
Age: 25, Sex : M
Salary :2300

还有更多用于从数据库中获取记录的快捷方法.如果您有兴趣,请浏览获取结果,否则请继续下一部分.

更新操作

UPDATE对任何数据库的操作意味着更新一个或多个已在数据库中可用的记录.以下是将SEX更新为"M"的所有记录的过程.在这里,我们将所有男性的年龄增加一年.这将需要三个步骤 :

  • 根据所需条件准备SQL查询.这将使用准备方法完成.

  • 执行SQL查询以从数据库中选择所有结果.这将使用执行方法完成.

  • 释放语句句柄.这将使用完成方法完成.

  • 如果一切顺利,则提交此操作否则你可以回滚完成交易.

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   sth = dbh.prepare("UPDATE EMPLOYEE SET AGE = AGE + 1 WHERE SEX = ?")
   sth.execute('M')
   sth.finish
   dbh.commit
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
   dbh.rollback
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

DELETE Operation

如果要从数据库中删除某些记录,则需要执行DELETE操作.以下是从EMPLOYEE中删除AGE超过20的所有记录的过程.此操作将采取以下步骤.

  • 根据所需条件准备SQL查询.这将使用准备方法完成.

  • 执行SQL查询以从数据库中删除所需的记录.这将使用执行方法完成.

  • 释放语句句柄.这将使用完成方法完成.

  • 如果一切顺利,则提交此操作否则你可以回滚完成交易.

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   sth = dbh.prepare("DELETE FROM EMPLOYEE WHERE AGE > ?")
   sth.execute(20)
   sth.finish
   dbh.commit
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
   dbh.rollback
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

执行交易

事务是一种确保数据一致性的机制.交易应具有以下四个属性 :

  • 原子性 : 交易完成或根本没有任何事情发生.

  • 一致性 : 交易必须以一致的状态开始,并使系统处于一致状态.

  • 隔离 : 在当前交易之外,交易的中间结果不可见.

  • 耐久性 : 提交事务后,即使系统出现故障,效果也会持续存在.

DBI为提供了两种方法提交回滚一个事务.还有一种称为 transaction 的方法可用于实现事务.有两种简单的方法来实现事务和减去;

方法I

第一种方法使用DBI的提交 rollback 显式提交或取消事务的方法 :

dbh['AutoCommit'] = false # Set auto commit to false.
begin
   dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 WHERE FIRST_NAME = 'John'")
   dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 WHERE FIRST_NAME = 'Zara'")
   dbh.commit
rescue
   puts "transaction failed"
   dbh.rollback
end
dbh['AutoCommit'] = true

方法II

第二种方法使用交易方法.这更简单,因为它需要一个包含构成事务的语句的代码块. 事务方法执行块,然后自动调用 commit rollback ,具体取决于块是成功还是失败:

dbh['AutoCommit'] = false # Set auto commit to false.
dbh.transaction do |dbh|
   dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 WHERE FIRST_NAME = 'John'")
   dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 WHERE FIRST_NAME = 'Zara'")
end
dbh['AutoCommit'] = true

COMMIT操作

提交是操作,它向数据库发出绿色信号以完成更改,并且在此操作之后,不能恢复任何更改.

这是一个调用提交的简单示例方法.

dbh.commit

ROLLBACK操作

如果您对一项或多项更改不满意,并且想要完全恢复这些更改,请使用回滚方法.

这是一个调用回滚方法的简单示例.

dbh.rollback

断开数据库

要断开数据库连接,请使用disconnect API.

dbh.disconnect

如果用户使用disconnect方法关闭数据库连接,则任何未完成的交易由DBI回滚.但是,不要依赖于任何DBI的实现细节,您的应用程序最好明确地调用提交或回滚.

处理错误

那里有很多错误来源.一些示例是执行的SQL语句中的语法错误,连接失败,或者对已经取消或已完成的语句句柄调用fetch方法.

如果DBI方法失败,则DBI引发一个例外. DBI方法可能引发几种类型的异常,但两个最重要的异常类是 DBI :: InterfaceError DBI :: DatabaseError .

这些类的异常对象有三个名为 err errstr state 的属性,它们代表错误号,描述性错误字符串,以及标准错误代码.这些属性在下面和下面解释;

  • 错误 : 如果DBD不支持,则返回发生的错误的整数表示或 nil .例如,Oracle DBD返回 ORA-XXXX 错误消息的数字部分.

  • errstr : 返回发生错误的字符串表示.

  • state : 返回发生的错误的SQLSTATE代码.SQLSTATE是一个长度为五个字符的字符串.大多数DBD都不支持这个并返回nil.

您在大多数示例中都看到了以下代码 :

rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
   dbh.rollback
ensure
   # disconnect from server
   dbh.disconnect if dbh
end

获取有关调试信息您的脚本在执行时正在执行的操作,您可以启用跟踪.为此,必须首先加载dbi/trace模块,然后调用控制跟踪模式和输出目标的 trace 方法 :

require "dbi/trace"
..............

trace(mode, destination)

模式值可以是0(关闭),1,2或3,目标应该是IO对象.默认值分别为2和STDERR.

带方法的代码块

有一些方法可以创建句柄.可以使用代码块调用这些方法.使用代码块和方法的优点是它们提供代码块的句柄作为其参数,并在块终止时自动清理句柄.很少有例子可以理解这个概念.

  • DBI.connect : 此方法生成数据库句柄,建议在块的末尾调用 disconnect 以断开数据库连接.

  • dbh.prepare : 此方法生成一个语句句柄,建议在块结束时完成.在块中,您必须调用 execute 方法来执行该语句.

  • dbh.execute &minus ;除了我们不需要在块中调用execute之外,此方法类似.语句句柄自动执行.

示例1

DBI.connect 可以获取代码块,将数据库句柄传递给它,并自动断开块末尾的句柄,如下所示.

dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123") do |dbh|

示例2

dbh.prepare 可以采用代码块,传递语句处理它,并自动调用块结尾处的完成,如下所示.

dbh.prepare("SHOW DATABASES") do |sth|
   sth.execute
   puts "Databases: " + sth.fetch_all.join(", ")
end

示例3

dbh.execute 可以接受代码块,将语句句柄传递给它,并在块的末尾自动调用finish,如下所示;

dbh.execute("SHOW DATABASES") do |sth|
   puts "Databases: " + sth.fetch_all.join(", ")
end

DBI 交易方法还采用了上面已经描述的代码块.

特定于驱动程序的函数和属性

DBI允许数据库驱动程序提供其他特定于数据库的函数,可由用户通过任何Handle对象的 func 方法调用.

支持特定于驱动程序的属性,可以设置或者使用 [] = [] 方法.

Sr.No.功能&说明
1

dbh.func(:createdb,db_name)

创建一个新数据库.

2

dbh.func(:dropdb,db_name)

删除数据库.

3

dbh.func(:reload)

执行重新加载操作.

4

dbh.func(:shutdown)

关闭服务器.

5

dbh.func(:insert_id)=> Fixnum

返回连接的最新AUTO_INCREMENT值.

6

dbh.func(:client_info)=>字符串

按版本返回MySQL客户端信息.

7

dbh.func(:client_version)=> Fixnum

按版本返回客户信息.它类似于:client_info但它返回一个fixnum而不是sting.

8

dbh.func(:host_info)=>String

返回主机信息.

9

dbh.func(:proto_info)=> Fixnum

返回用于通信的协议.

10

dbh.func(:server_info)=>String

按版本返回MySQL服务器信息.

11

dbh.func(:stat)=>String

返回数据库的当前状态.

12

dbh.func(:thread_id)=> Fixnum

返回当前线程ID.

示例

#!/usr/bin/ruby

require "dbi"
begin
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123") 
   puts dbh.func(:client_info)
   puts dbh.func(:client_version)
   puts dbh.func(:host_info)
   puts dbh.func(:proto_info)
   puts dbh.func(:server_info)
   puts dbh.func(:thread_id)
   puts dbh.func(:stat)
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
ensure
   dbh.disconnect if dbh
end

这将产生以下结果 :

5.0.45
50045
Localhost via UNIX socket
10
5.0.45
150621
Uptime: 384981  Threads: 1  Questions: 1101078  Slow queries: 4 \
Opens: 324  Flush tables: 1  Open tables: 64  \
Queries per second avg: 2.860