Ruby访问操作Oracle数据库的例子

1. DDL SQL:创建新表

#createStatesTable.rb
require 'dbi'

#数据库连接字符串:包括 DBI:OCI8:ORCL 字符串以及用户名和口令
#OCI8 部分指的是 Ruby/OCI8 驱动程序,ORCL 部分指的是数据库服务。
dbh = DBI.connect('DBI:OCI8:ORCL', 'hr', 'hr')
dbh.do("CREATE TABLE states (
           id CHAR(2) PRIMARY KEY,
       name VARCHAR2(15) NOT NULL,
       capital VARCHAR2(25) NOT NULL)")
dbh.disconnect 

 

2. DML SQL

2.1. INSERT
#populateStatesTable.rb
require 'dbi'

dbh = DBI.connect('DBI:OCI8:ORCL', 'hr', 'hr')
#注意问号在 INSERT 语句中用作占位符。
sqlInsert = "INSERT INTO states (id, name, capital)
                         VALUES (?, ?, ?)"
dbh.do(sqlInsert, "AL", "Alabama", "Birmingham")
dbh.do(sqlInsert, "AZ", "Arizona", "Phoenix")
dbh.do(sqlInsert, "CO", "Colorado", "Denver")
dbh.do(sqlInsert, "FL", "Florida", "Tallahassee")
dbh.do(sqlInsert, "MA", "Maine", "Augusta")
dbh.do(sqlInsert, "PA", "Pennsylvania", "Philadelphia")
dbh.do(sqlInsert, "UT", "Utah", "Salt Lake City")
dbh.do(sqlInsert, "WA", "Washington", "Seattle")
dbh.do(sqlInsert, "WY", "Wyoming", "Cheyenne")
dbh.commit
dbh.disconnect

 

2.2.UPDATE
#updateStatesTable.rb
require 'dbi'

dbh = DBI.connect('DBI:OCI8:ORCL', 'hr', 'hr')
#用占位符
sqlCapitalsUpdate = "UPDATE states SET capital = ? WHERE id = ?"
dbh.do(sqlCapitalsUpdate, "Montgomery", "AL")
dbh.do(sqlCapitalsUpdate, "Harrisburg", "PA")
dbh.do(sqlCapitalsUpdate, "Olympia", "WA")
#不使用任何占位符
dbh.do("UPDATE states SET id = 'ME' WHERE name = 'Maine'")
dbh.commit
dbh.disconnect

 

2.3.DELETE

DELETE执行方式与其同等的 DML 语句 INSERT 和 UPDATE 的执行方式类似。

2.4.SELECT
#queryStatesTable.rb
require 'dbi'

dbh = DBI.connect('DBI:OCI8:ORCL', 'hr', 'hr')
#数据库查询的结果集。
rs = dbh.prepare('SELECT * FROM states')
rs.execute
while rsRow = rs.fetch do
   #内置的 p 函数打印出返回的行
   p rsRow
   #Alternative output: puts rsRow
   #Alternative output: pp rsRow
end
rs.finish
dbh.disconnect     

 

2.5.使用 DBI 以表格输出查询结果

 

清单 5 queryStatesTableFormatter.rb
require 'dbi'

dbh = DBI.connect('DBI:OCI8:ORCL', 'hr', 'hr')
rs = dbh.execute('SELECT * FROM states')
rows = rs.fetch_all
column_names = rs.column_names
rs.finish
DBI::Utils::TableFormatter.ascii(column_names, rows)
dbh.disconnect

 

2.6.使用 DBI 以XML 格式输出查询结果

 

# queryStatesTableXML.rb
require 'dbi'

dbh = DBI.connect('DBI:OCI8:ORCL', 'hr', 'hr')
rs = dbh.execute('SELECT * FROM states')
states_rows = rs.fetch_all
rs.finish
DBI::Utils::XMLFormatter.table(states_rows)
dbh.disconnect   

 

3. 存储过程。

3.1.访问 PL/SQL 内置存储过程 DBMS_UTILITY.DB_VERSION(接受两个 OUT 参数)
#builtInDBVersionCompat.rb
require 'dbi'

#使用位置绑定变量,将问号 (?) 放在数据库执行字符串中.
db_read_str = 'BEGIN DBMS_UTILITY.DB_VERSION(?, ?); END;'
dbh = DBI.connect('DBI:OCI8:ORCL', 'hr', 'hr')
#使用DBI::Handle(sth_db)函数方法
sth_db = dbh.prepare(db_read_str)
#使用从1开始的连续整数来引用值。
sth_db.bind_param(1, ' ' * 50)  # allow for up to 50 chars
sth_db.bind_param(2, ' ' * 50)  # allow for up to 50 chars
sth_db.execute
#Ruby符号(:bind_value)的使用
version = sth_db.func(:bind_value, 1)
puts "Oracle DB Version: " + version
compatibility = sth_db.func(:bind_value, 2)
puts "Oracle DB Compatibility: " + compatibility
dbh.disconnect     

 

3.2.运行内置的存储函数 DBMS_METADATA.GET_DDL返回创建表所需的 DDL。
#builtInGetDDL.rb
require 'dbi'

#使用名称绑定变量,放入的是 Ruby 符号(:out1、:in1 和 :in2)
db_read_str = 'BEGIN :out1 := DBMS_METADATA.GET_DDL(object_type=>:in1, '
db_read_str += 'name=>:in2); END;'
puts db_read_str
dbh = DBI.connect('DBI:OCI8:ORCL', 'hr', 'hr')
sth_db = dbh.prepare(db_read_str)
#通过名称引用绑定变量以访问其值。
sth_db.bind_param("out1", ' ' * 20000 )
sth_db.bind_param("in1", "TABLE")
sth_db.bind_param("in2", "STATES")
sth_db.execute
puts sth_db.func("bind_value", "out1")
dbh.disconnect

4.访问安裝Oracle的操作系统

4.1.访问环境变量
#displayOracleENV.rb
#使用每种方法对 ENV 散列进行迭代,每行打印一个环境变量及其值。
ENV.each {|key ,value| print key, "=", value, "\n"}

 

4.2.访问各种配置和其他文件(如 init.ora 文件)
4.2.1.查看init.ora文件中的键值设置.

 

#displayInitOra.rb
=begin
檔案从命令行和基于控制台的用户提示符获得输入。
首先在命令行使用预定义的 Ruby 变量ARGV,尝试获取文件路径和文件名。
如果不奏效,然后提示用户输入路径。
如果用户不提供路径和文件名,则使用硬编码的路径(包括文件名)。
=end

fileName = ARGV.to_s
# example of if statement
if fileName.size < 1
  print "Enter init.ora path and name: "
  #删除从用户控制台输入中检索到的基于字符串的文件名末尾的记录分隔符。
  #惊叹号表明该方法正在执行有可能对对象危险的操作。
  fileName = gets.chomp!
end

#example of unless statement
unless fileName.size > 1
  fileName = "C:\\oracle\\product\\10.1.0\\admin\\orcl\\init.ora"
end
print "File Name: " + fileName + "!"
theFile = File.new(fileName, "r")  # read the file
text = theFile.read  # copy file's contents into string
theFile.close        # string holds file contents; close file
#使用Regexp处理正则表达式,应用于字符串的scan方法,返回与所提供的正则表达式匹配的字符串中的子字符串。
regExp = Regexp.new('^.+=.+$')
puts text.scan(regExp)
 4.2.2.比较两个 init.ora 文件并报告它们之间的差异。
#diffInitOra.rb
=begin
读入作为命令行参数传入的两个 init.ora 文件的内容。
使用pp库打印出文件的名称,如果其中一个文件未打开,则显示该文件关闭。
在从文件中读取的两个字符串之间用一个减号确定两个文件之间的差异。
=end
require 'pp'

unless ARGV.size == 2
  print "Usage: ruby arrayMagic.rb firstFile secondFile"
  exit
end

firstFile = File.new(ARGV[0], "r")
secondFile = File.new(ARGV[1], "r")
regExp = Regexp.new('^.+=.+$')
text1 = firstFile.read.scan(regExp)
text2 = secondFile.read.scan(regExp)
firstFile.close
pp firstFile
puts text1-text2, "\n"
pp secondFile
puts text2-text1
secondFile.close

5.Ruby 异常处理

5.1.使用 Ruby 的异常处理机制的示例。
#rubyExceptions.rb
=begin
关键字begin引发(抛出)异常的代码块的起始位置。
关键字raise供脚本引发(抛出)自己的异常。
关键字rescue与Java的catch关键字类似。
关键字ensure与Java的finally关键字类似,用于执行功能,无论是否遇到异常。
=end

fileName = ARGV.to_s

#obtain file name if not provided on command-line
if fileName.size < 1
  print "Enter init.ora path and name: "
  fileName = gets.chomp!
end

#ensure something has been provided for file name
begin
  if fileName.size < 1
    raise ArgumentError, "No valid file name provided" + "\n"
  end
rescue ArgumentError => argErr
  print argErr
  raise  # re-raise this exception and force script termination
end

#get file contents
begin #Begin exception handling block for file I/O
  theFile = File.new(fileName, "r")
  text = theFile.read
  theFile.close
rescue IOError
  print "I/O Error: Problem accessing file " + fileName + "\n"
  exit
rescue Errno::ENOENT
  print "ENOENT: Cannot find file " + fileName + "\n"
  exit
rescue Errno::EPERM
  print "EPERM: Insufficient rights to open " + fileName + "\n"
  raise
rescue Exception  # Catch-all: More exceptions captured than with "rescue" alone
  print "Generic error rescued (captured) during file I/O attempt." + "\n"
  raise
else
  print "Good news!  There was no problem with file I/O for " + fileName + "\n"
ensure
  print "Good or bad, file handling attempt is now complete!\n"
end #End exception handling block for file I/O

#obtain text string for regular expression
print "Enter regular expression pattern: "
pattern = gets.chomp!

begin #Begin exception handling block for regular expression
  regExp = Regexp.new(pattern)
rescue RegexpError
  print "Problem with regular expression " + regExp.to_s + "\n"
  exit  # Nothing to be done with a bad regular expression
ensure
  print "Regular expression evaluated was: " + regExp.to_s + "\n"
end #End exception handling block for regular expression

puts text.scan(regExp)

 
下图显示了运行脚本三次的结果。

第一次运行该脚本时,故意提供了一个未知的文件名以调用文件处理异常处理。
第二次运行该脚本时用正确的文件名演示 else 块的执行,并允许执行转至与正则表达式处理相关的代码块。第二次执行该脚本时,提供了一个错误的表达式以演示 RegexpError 的处理。
第三次运行该脚本时演示了脚本的完整运行,不引发异常。所有这三次运行都演示了 ensure 块的执行,因为无论是否引发(抛出)异常,所有异常处理过程中始终调用该块。

 

 

5.2.Ruby DBI 异常处理
=begin
rubyDbExceptions.rb
代码将导致抛出一个异常,因为存在一个“while 0”循环(0 的值为“true”),该循环将重复执行,直至抛出异常。由于在抛出DBI::DatabaseError之前重复调用DBI.connect 而没有正确关闭打开的连接,因此的确会抛出该异常。在这种情况下,显示的错误代码为 12520(特定于 Oracle 的数据库错误代码),错误字符串为“ORA-12520:TNS:listener could not find available handler for requested type of server.”这些输出代码和字符串值是使用适当的 DBI::DatabaseError 属性(err 和 errstr)输出的。

如果用一个数据库操作(如 SELECT 语句)替换while 循环(故意强制数据库错误),rescue、else 和 ensure 块将被激活。如果仍出现任何异常(如完整性约束),将调用适当的“rescue”块。如果没有遇到指定了 rescue 块的异常,“else”块中的代码将执行并提交事务。在任何情况下,无论是否抛出异常,都将执行“ensure”代码块,并相应地断开与处理程序的连接。

编写 Ruby 脚本时,不一定需要捕获 (rescue) 异常(考虑 Java 的非强制异常)。然而,如果您知道可能出现某些异常并希望您的脚本针对这些情况进行某些处理(如立即退出或者打印出某些与异常相关的详细信息),Ruby 可以简化异常处理。如果您不想将 rescue-else-ensure 块与抛出异常的代码块相关联,该脚本将突然停止该代码块的执行,将显示常规异常信息,执行下一个代码块。
=end

require 'dbi'

begin
  counter = 0
  while 0  # "infinite" loop because 0 resolves to "true" for Ruby conditional
    dbh = DBI.connect('DBI:OCI8:ORCL', 'hr', 'hr')
    counter += 1
    puts "DB Connection #" + counter.to_s + "\n"
    #Intentionally NOT closing with dbh.close to force DatabaseError.
  end
rescue DBI::DataError => dataErr
  dbh.rollback
  puts "DB error due to problem with data"
  puts "Error Code: #{dataErr.err}"
  puts "Error Message: #{dataErr.errstr}"
  puts "DB rollback.\n"
rescue DBI::IntegrityError => integErr
  # Example: Trying to insert same value for unique column twice.
  dbh.rollback
  puts "DB error due to integrity problem."
  puts "Error Code: #{integErr.err}"
  puts "Error Message: #{integErr.errstr}"
  puts "DB rollback.\n"
rescue DBI::InternalError => internErr
  dbh.rollback
  puts "DB error database internal error."
  puts "Error Code: #{internErr.err}"
  puts "Error Message: #{internErr.errstr}"
  puts "DB rollback.\n"
rescue DBI::NotSupportedError => notSuppErr
  dbh.rollback
  puts "DB feature not supported."
  puts "Error Code: #{notSuppErr.err}"
  puts "Error Message: #{notSuppErr.errstr}"
  puts "DB rollback.\n"
rescue DBI::OperationalError => opErr
  dbh.rollback
  puts "DB error due to problems with operation of database."
  puts "Error Code: #{opErr.err}"
  puts "Error Message: #{opErr.errstr}"
  puts "DB rollback.\n"
rescue DBI::ProgrammingError => dbProgErr
  # Example: Bad column name in SQL statement.
  dbh.rollback
  puts "DB error due to programming problem.\n"
  puts "Error Code: #{dbProgErr.err}"
  puts "Error Message: #{dbProgErr.errstr}"
  puts "DB rollback.\n"
rescue DBI::DatabaseError => dbErr
  # Catch-all for all database exceptions.
  dbh.rollback
  puts "Database exception encountered."
  puts "Error Code: #{dbErr.err}"
  puts "Error Message: #{dbErr.errstr}"
  puts "DB rollback."
rescue DBI::InterfaceError => ifError
  dbh.rollback
  puts "Problem with DBI interface encountered."
rescue RuntimeError
  dbh.rollback
  puts "Unknown error (not DB or DBI) encountered."
else
  puts "DB commit.\n"
  dbh.commit
ensure
  puts "Disconnecting database handler."
  dbh.disconnect
end     
 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值