从 Ruby on Rails 连接到 Oracle

日期: 2008-02-26 作者:Obie Fernandez 来源:TechTarget中国

  在使用 Java 时,有两种针对 Oracle 的常见驱动程序:纯 Java (又叫做瘦)驱动程序和原生 OCI 驱动程序。在写作这篇文章的时候,还没有和基于 JDBC 的 Java 瘦驱动程序类似的纯 Ruby 驱动程序。

  要连接到 Oracle,用户必须安装 Ruby/Oracle 调用接口 (OCI8) 库 — 一个基于 Ruby/DBI (数据库接口模块)的数据库驱动程序。RubyDBI 提供了一个与数据库无关的、类似于 JDBC 或 ODBC 的接口,来实现 Ruby 和数据库之间的交互。Ruby OCI8 驱动程序通过标准的 Oracle 客户端软件连接到 Oracle 8 到 10 的所有版本。OCI8 是一个 Ruby 包装器,用本地 C 代码编写,实际的交互就由它来完成。

  非 windows 开发人员可以通过输入 sudo gem install ruby-oci8 来进行安装。Windows 开发人员可以先从 www.rubyforge.org/projects/ruby-oci8 上下该载驱动程序的二进制版本,然后手动安装:

  ruby ruby-oci8-0.1.16-mswin32.rb

  可以通过下面的命令行 Ruby 程序查询一个包含演示 (HR) 模式的数据库,简单检测您所下载的 Ruby OCI8 驱动程序。替换下面命令中 Oracle 数据库的名称和口令:

  set oracle_sid=xe

  ruby -r oci8 -e "OCI8.new(‘hr’, ‘password’).exec(‘SELECT * FROM jobs ORDER BY 1’) {|r| puts r.join}"

  如果连接和查询成功,输出应如下所示:

  AC_ACCOUNT | Public Accountant | 4200 | 9000

  AC_MGR | Accounting Manager | 8200 | 16000

  AD_ASST | Administration Assistant | 3000 | 6000

  AD_PRES | President | 20000 | 40000

  AD_VP | Administration Vice President | 15000 | 30000

  FI_ACCOUNT | Accountant | 4200 | 9000

  FI_MGR | Finance Manager | 8200 | 16000

  HR_REP | Human Resources Representative | 4000 | 9000

  IT_PROG | Programmer | 4000 | 10000

  MK_MAN | Marketing Manager | 9000 | 15000

  MK_REP | Marketing Representative | 4000 | 9000

  PR_REP | Public Relations Representative | 4500 | 10500

  PU_CLERK | Purchasing Clerk | 2500 | 5500

  PU_MAN | Purchasing Manager | 8000 | 15000

  SA_MAN | Sales Manager | 10000 | 20000

  SA_REP | Sales Representative | 6000 | 12000

  SH_CLERK | Shipping Clerk | 2500 | 5500

  ST_CLERK | Stock Clerk | 2000 | 5000

  ST_MAN | Stock Manager | 5500 | 8500

  Rails 配置

  Rails 用于连接到数据库的参数存放在您的 Rails 应用程序目录中的 config/database.yml 中。下面的例子引用了主机 xe,它对应 tnsnames.ora 中的一项。使用了三种模式,分别用不同的用户名指定。

  development:

  adapter:oci

  host:xe

  username:development

  password:password

  test:

  adapter:oci

  hostxe

  username:test

  password:password

  production:

  adapter:oci

  host:xe

  username:production

  password:password

  也可以将 Oracle Easy Connect Naming 和 Ruby OCI8 驱动程序结合使用。用一个 Oracle Easy 连接字符串替换主机字段中的 SID,如下所示:

  development:

  adapter:oci

  host://server:port/instance_name

  username:development

  password:password

  身份验证

  和大多数的三层应用程序体系结构一样,Rails 假设使用一套证书(在 database.yml 中指定)对 Oracle 进行身份验证。指定的证书必须有足够的权限来执行 Rails 应用程序的任何操作。

  如果出于安全的考虑,不想把证书以明文的形式包含在配置文件中,您可以利用 database.yml 允许通过 ERb 标记使用动态内容的特性。语法与使用 标记将参数值插入 Rails 视图模版的语法相同。

  下面的例子从启动时设置的环境变量中获取用户名和口令:

  production:

  adapter:oci

  host:xe

  username:

  password:

  传递身份验证 (Pass-Through Authentication)

  目前还没有一个从 Rails 应用程序到 Oracle 的所谓的传递身份验证(一个终端用户使用他或她的 Oracle 证书来验证身份。验证通过后,对该应用程序的使用则受 Oracle 定义的访问权限和限制范围的控制)的标准方法。与 Rails 相关的涉及传递身份验证的自定义解决方案在理论上是可行的,但也存在各种各样的应用和性能问题。

  比如,从理论上来讲,我们总可以使用已登录用户的证书创建一个到数据库的新连接。这可以通过在控制器的 before_filter 方法中建立一个连接(使用该用户的证书)完成。相应的,取消连接需要在 after_filter 方法中手动完成。与其他问题相比,这种方法的速度非常慢,因为需要为每一个请求建立一个连接。

  难得就不可简单地将 Oracle 连接缓存在一个用户会话中吗?很遗憾,不能;因为 Rails 应用程序没有像 JEE 应用程序那样可以在请求间保持活动状态的内存会话存储。所有会话内容与文件系统的序列化和存储、数据库或分布式缓存相关。

  假定已经找到在现有连接上验证指定用户身份的难点,那么传递身份验证与 ActiveRecord 的结合可能会提供某些价值。

  比如,行级安全性对于一个在数据库级指定的用户来说可以透明的指定该用户可见的对象,而无需任何实现代码。此外,ActiveRecord 的属性动态生成特性也是一大亮点,因为它可以将列级安全性透明的反射到对象模型中。因为属性是动态读取的,所以该模型实例只包含与已登录用户可见的列相匹配的属性。不过要记住,虽然由于性能原因在生产模式下缓存属性信息,但是另一个优化使传递身份验证变成了一个性能问题。

  对于通过授权实现的表级安全性,您可以假定一旦 SQL 由于权限问题运行失败,Oracle 会从驱动程序引发异常。您可以捕捉这些异常并进行妥善处理,但是如果当作出一次尝试时一个指定的操作是有效的,这种方法存在的问题就不会出现。比如,如果您想根据用户的插入权限在一张表上禁用一个“create”按钮,那么在执行插入操作之前您无法获知他的权限。

  可能的变通方法就是在首次建立该连接的时候,将该用户的所有授权和权限信息加载到会话中。然后,可以使用这些授权和权限信息在视图中提供安全特性(根据权限隐藏/禁用按钮),或向模型添加安全性(在执行这项操作之前先用 before_save 和 before_update 等回调方法进行权限检查)。当然,这都是理论上的分析,而读取权限信息时可能遇到的困难也是未知的,尤其是在通过存储过程实现时。

  使用多个数据库

  建立一个可以和多个数据库交互的 Rails 应用程序一点都不复杂。您只要在 database.yml 文件中指定额外的数据库连接参数。比如,假设您需要访问另一个 Oracle 数据库来读取库存数据:

  inventory:

  adapter:oci

  host:xe

  username:inventory

  password:password

  然后,定义一个模型(名为 Inventory)来读取库存数据:

  class Forum < ActiveRecord::Base

  self.connection = "inventory"

  end

  Rails 应用程序部署为独立的服务器进程池,并且对于每个 rails 请求均按进程维护和重用一个数据库连接。我们通常分别使用 ActiveRecord::Base.establish_connection 和 ActiveRecord::Base.connection 来建立和检索连接。所有继承 ActiveRecord::Base 的类都将使用这个连接。您也可以为某些特定的模型建立一个为某个类所特有的连接(如前面所示),然后这个类和它所有的子类将会转而使用这个显示指定的连接。

  ActiveRecord 在 ActiveRecord::Base 中将一个连接池作为按模型类名索引的散列。当请求连接时,retrieve_connection 方法会向上遍历类层次结构,直到在连接池中找到一个连接。

  优化

  Rails 现在还不支持在 SQL 查询中将变量和 Oracle 绑定,这对性能造成了一些负面影响。Rails (1.2) 的当前版本将 Oracle 连接选项 cursor_sharing 设置为 similar,这通过在数据库级自动将文字转换为绑定变量,显著改善了性能。此外,它还将预取行数设置为 100。

  但无论是游标共享还是预取行数设置都不是理想的解决方案。虽然这两个方案都有可能给服务器带来额外的负担,但是大多数开发人员只片面报告他们连接 Oracle 的 Rails 应用程序在性能方面的显著改进,这使我们误以为这两个方案在大多数情况下都有效。但您的体会可能与此不同。

  如果您需要额外的性能优化,Ruby OCI 驱动程序可以利用多种其他属性来调整数据库连接,只是 Rails 没有提供一个设置这些属性的标准方法。要了解更多优化方案,包括设置诸如 prefetch-rows 等选项的方法,请访问 www.ruby-forum.com/topic/86831

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

相关推荐