使用Ruby DBI模塊

使用Ruby DBI模塊

原著 Paul DuBois   [email protected]

翻譯:liubin  2004/11/9  http://www.ruby-cn.org/  
原文地址:http://www.kitebird.com/articles/ruby-dbi.html

 

文檔版本: 1.02
最後更新: 2003-05-27

目錄


序論

Ruby DBI模塊爲ruby程序訪問數據庫提供了一個與數據庫無關的接口,就像perl的DBI模塊一樣。這篇文章將講述如何編寫基於DBI的ruby程序。這篇文章是對DBI規範文檔(specification documents)的補充,而不是要替代規範文檔,更多的信息請參見“資源”一節。

Ruby的DBI 模塊架構分爲兩層:

  • 數據庫接口層(database interface DBI)。這層是與數據庫無關的,它提供一些與你具體使用的數據庫無關的通用的訪問方法。。
  • 數據庫驅動層(database driver DBD)。這一層是與數據庫相關的,不同的驅動用來訪問不同的數據庫。一個驅動用來訪問mysql,另一個用來訪問postgresql,每一個具體的數據庫都有不同的驅動。每個驅動解釋DBI層傳送的請求,並轉換成對應於具體數據庫的請求,發送到數據庫。
本文的例子用到的數據庫都是mysql的,但多數也可以適用其他數據庫驅動。

準備


Ruby DBI模塊包括了實現一般DBI的代碼,和一些DBD層的驅動,很多這些驅動需要你安裝額外的軟件。比如,用於Mysql的驅動使用ruby寫成,與ruby mysql模塊綁定,而ruby mysql驅動是c語言寫的,幫定了mysql 的c語言 客戶端API。這就是說,你要是想用DBI訪問MySql數據庫,ruby mysql模塊和C API這兩者都需要安裝。更多關於ruby mysql 模塊的信息,參見“資源”一節。這裏我們假定你已經安裝了ruby mysql,並且可以用於DBI。

安裝


一旦你滿足了前面的條件,就可以安裝Ruby DBI模塊,可以從這裏取得:
   http://ruby-dbi.sourceforge.net/

DBI模塊以壓縮的tar格式發佈,下載之後應該解壓縮,比如,現在版本是0.0.19,如下即可解壓縮:
   % tar zxf ruby-dbi-all-0.0.19.tar.gz
   % gunzip < ruby-dbi-all-0.0.19.tar.gz | tar xf -
解壓縮之後,進入軟件包的頂層目錄下,用setup.rb腳本進行配置。一般的配置命令都像這樣,在config後面沒有參數:
   % ruby setup.rb config
這條命令設置了默認安裝所有的驅動,更有效的辦法是在剛纔的config 後面加上--with參數,指定需要安裝的部分。比如,爲了配置只安裝主DBI模塊和MYSQL  DBD 驅動,運行下面命令:
   % ruby setup.rb config --with=dbi,dbd_mysql
配置完要安裝的軟件之後,就可以build和安裝了:
   % ruby setup.rb setup
   % ruby setup.rb install
運行install需要root權限。

本文的後面部分將使用下面的表示約定:

  • "DBI module" 指的是包括DBI層和DBD層都在內的集合,除非上下文說明了這層是獨立於數據庫。
  • "DBD::Mysql" 指的是用於DBI的特定於MySQL的數據庫驅動。
  • "Ruby MySQL 模塊" 指的是用於建造DBD::Mysql的基礎模塊。

一個簡單的DBI腳本


安裝完ruby DBI模塊之後,你就可以在你的Ruby程序中訪問MYSQL數據庫了。假設我們的數據庫在本機運行,即localhost,數據庫名爲test,通過一個用戶名爲testuser,密碼是testpass的用戶訪問。我們可以用root登陸到mysql程序,然後執行下列命令建立這樣的一個用戶:

   mysql> GRANT ALL ON test.* TO 'testuser'@'localhost' IDENTIFIED BY 'testpass';
如果test數據庫不存在,用下面的命令創建它:
   mysql> CREATE DATABASE test;
如果你想用不同的數據庫,服務器,用戶和密碼的話,只需要將例子裏對應的值換成你自己的就行了。

下面這個腳本, simple.rb, 是一個很短的DBI程序,它先連接的數據庫,然後查詢了數據庫的版本,並顯示出來,然後斷開連接。你可以從“資源”裏提供的鏈接下載這段代碼,或者把它拷貝到文本編輯器中:

   # simple.rb - simple MySQL script using Ruby DBI module
   require "dbi"
   begin
       # connect to the MySQL server
       dbh = DBI.connect("dbi:Mysql:test:localhost", "testuser", "testpass")
       # 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
simple.rb 展現了DBI最基本的一些概念,下面的討論將會講述他是如何工作的,然後更後面還要講述DBI的其他一些方面。

simple.rb以一行require 開始,把DBI模塊引入近來;沒有這一行的話,DBI方法將會出錯,後面的代碼包括在一個 begin/rescue/ensure 結構中:

  • begin 部分處理了所有的數據庫請求。
  • rescue 部分用來處理出錯信息,它將獲取出錯信息,並顯示出來。
  • ensure 塊確保程序不管出錯與否,最後都將關閉數據庫連接。
方法connect 用來和數據庫服務器建立一個連接,並返回這個連接。第一個參數是數據源名(data source name DSN),它指定了驅動名稱(Mysql用於MySql服務器),默認得數據庫名和服務器的機器名,第二、三個參數是用戶和密碼。還有其他的DSN寫法, 將在後面“再論連接數據庫”中說明。

simple.rb 用數據庫句柄(database handle)調用方法select_one, 這個方法向服務器發送一個查詢語句,並且將結果集的第一行作爲數組返回給調用者。“SELECT VERSION() ”返回返回單個值,所以版本信息將存在row[0]中,這是這個數組的第一個也是唯一一個元素。運行這個程序,結果像這樣:

   % ruby simple.rb
   Server version: 4.0.13-log
如果出錯,會導致拋出異常,異常可能各種各樣,但多數都屬於數據庫錯誤,多爲DatabaseError 異常,這種異常對象包括err和errstr屬性,err是錯誤編號,errstr是錯誤消息。simple.rb得到這些異常的值並打印它們,但是忽略了其他的異常,這時候如果出現了其他異常,則將會拋給ruby執行環境。

simple.rb 用disconnect方法來斷開與數據庫的連接,這在ensure裏執行,這樣就使得不管出錯與否,數據庫連接都會被斷開。

處理查詢


Ruby DBI 提供了很多方法用來執行查詢語句。這裏將討論這中間的一部分,但還有其他的。

多數的例子都用到了表people,它的結構如下:

   CREATE TABLE people
   (
       id INT UNSIGNED NOT NULL AUTO_INCREMENT,    # ID number
       name CHAR(20) NOT NULL,                     # name
       height FLOAT,                               # height in inches
       PRIMARY KEY (id)
   );

處理不返回結果集的查詢


如果一個語句不需要返回結果,可以用數據庫句柄的do方法,這個方法的參數爲要執行的sql語句,返回受影響的行數。下面的例子創建了表people,並插入了幾條記錄,都用了do方法:


   dbh.do("DROP TABLE IF EXISTS people")
   dbh.do("CREATE TABLE people (
           id INT UNSIGNED NOT NULL AUTO_INCREMENT,
           PRIMARY KEY (id),
           name CHAR(20) NOT NULL,
           height FLOAT)")
   rows = dbh.do("INSERT INTO people (name,height)
           VALUES('Wanda',62.5),('Robert',75),('Phillip',71.5),('Sarah',68)")
   printf "%d rows were inserted/n", rows

需要注意的是insert語句返回了一個值,即插入的行數,並把它打印了出來。

處理返回結果集的查詢


像select和show這樣的語句是要返回行記錄的,處理這樣的語句,要先向服務器提交查詢,處理查詢產生的每條記錄,然後把結果集銷燬。

一種辦法是調用prepare產生一個statement 句柄,用這個句柄來執行查詢,取回結果,然後釋放結果集:

   sth = dbh.prepare(statement)
   sth.execute
   ... fetch rows ...
   sth.finish
或者直接把語句發送給數據庫連接句柄去執行而不用調用prepare:
   sth = dbh.execute(statement)
   ... fetch rows ...
   sth.finish
同樣也有很多方法從執行完的語句取得結果,可以在一個循環裏調用fetch方法直到返回nil爲止:
   sth = dbh.execute("SELECT * FROM people")
   while row = sth.fetch do
       printf "ID: %d, Name: %s, Height: %.1f/n", row[0], row[1], row[2]
   end
   sth.finish
fetch 也可以用作一個 iterator來用, 也用each.方法。下面的兩個是一樣的作用:
   sth = dbh.execute("SELECT * FROM people")
   sth.fetch do |row|
       printf "ID: %d, Name: %s, Height: %.1f/n", row[0], row[1], row[2]
   end
   sth.finish
   sth = dbh.execute("SELECT * FROM people")
   sth.each do |row|
       printf "ID: %d, Name: %s, Height: %.1f/n", row[0], row[1], row[2]
   end
   sth.finish
fetcheach 都產生了 DBI::Row 對象, 這個對象提供了訪問他們內容的方法:
  • 可以用by_indexby_field 來通過順序或者名字訪問字段值:
       val = row.by_index(2)
       val = row.by_field("height")
    
  • 字段值也可以將row對象當成數組來取得:
       val = row[2]
       val = row["height"]
    
  • 迭代方法 each_with_name 生成每個字段名和它們的值:
       sth = dbh.execute("SELECT * FROM people")
       sth.each do |row|
           row.each_with_name do |val, name|
               printf "%s: %s, ", name, val.to_s
           end
           print "/n"
       end
       sth.finish
    
  • DBI::Row 對象提供了一個方法 column_names 來得到一個包含每個字段名的數組。  field_namescolumn_names的別名。
其他的返回行數據的方法包括fetch_array和fetch_hash,他們不返回DBI::Row對象,而是將下一行數據作爲數組或者哈希返回, 如果已經到結果集的最後的話,也會返回nil。fetch_hash返回哈希結構,由列名作爲key,而列的值作爲這個key對應的值。這兩個方法可以獨立使用,也可以在迭代中使用。下面例子用了hash方法:
   sth = dbh.execute("SELECT * FROM people")
   while row = sth.fetch_hash do
       printf "ID: %d, Name: %s, Height: %.1f/n",
               row["id"], row["name"], row["height"]
   end
   sth.finish
   sth = dbh.execute("SELECT * FROM people")
   sth.fetch_hash do |row|
       printf "ID: %d, Name: %s, Height: %.1f/n",
               row["id"], row["name"], row["height"]
   end
   sth.finish
你也可以不用依照 “查詢--取結果--完成”這種順序來執行你的語句,數據庫句柄可以一次取回所有的結果:
   row = dbh.select_one(statement)
   rows = dbh.select_all(statement)
select_one 執行一個查詢,然後將結果的第一行作爲一個數組返回,或者返回nil,如果沒有匹配記錄的話。select_all 返回一個 DBI::Row 的數組,(你可以用前面討論過得方法訪問裏面的內容)。如果沒有匹配結果,則返回空數組。注意不是nil。

  MySQL 驅動會檢查返回的結果集中的元數據(metadata),然後強制將這個字段的的值變爲對應的Ruby類型(比如,從people取得的id,name,height字段的值將會被轉變爲Fixnum,String和Float對象)。但是,如果一個列的值爲NULL,則用nil來表示,並且它的類型爲NilClass。還有就是這不是DBI規格說明書的硬性規定,所以有的驅動可能不會做這樣的工作。

引用,佔位符(placeholder)和參數綁定


Ruby DBI提供了佔位符機制,使得你可以不用在查詢語句中把數據值的字面值寫到裏面,而是用一些特殊的符號標記數據的位置,當你真的要執行的時候,用真實的數據值填充佔位符的位置。DBI會用數據值替換佔位符,完成對字符串等加引號,特殊字符的轉義(如果需要的話)等,而不必你自己去做,而且佔位符機制能很好的處理NULL值,你只需要提供一個nil值,它會自動被換成NULL放到查詢中。

下面例子解釋了它是如何工作的。加入你想向people表裏插入一條記錄,這個人的名字叫Na'il,這個名字包括一個單引號,他的身高是76英寸。在查詢語句中,用?來作爲插入值的佔位符,不需要引號括起來,然後將實際要插入的值作爲do的參數,如下:

   dbh.do("INSERT INTO people (id, name, height) VALUES(?, ?, ?)",
           nil, "Na'il", 76)
這條語句發送給數據庫的語句像這樣:
   INSERT INTO people (id,name,height) VALUES(NULL,'Na/'il',76)
這更適合於你要多次執行一個查詢,你可以先生成一個預處理語句語句,然後每次用數據值填充去執行。假如要導入的數據存在文本文件people.txt裏面,每一行了用tab分割,由name,height兩列組成,下面的代碼演示瞭如何從數據文件讀取數據,然後執行insert語句將每一行插入數據庫:
   # prepare statement for use within insert loop
   sth = dbh.prepare("INSERT INTO people (id, name, height) VALUES(?, ?, ?)")
   # read each line from file, split into values, and insert into database
   f = File.open("people.txt", "r")
   f.each_line do |line|
       name, height = line.chomp.split("/t")
       sth.execute(nil, name, height)
   end
   f.close
生成一個預處理語句,然後在循環中多次執行它,比用循環來直接執行有效多了,主要是因爲數據庫能爲預處理語句生成一個執行計劃,以後每次執行都會用這個執行計劃來執行,提高了效率。當然目前mysql還不支持這個功能,oracle支持。

如果想用佔位符的方法執行select語句,你應該先考慮一下是否用預處理語句:

  • 如果你用prepare 方法得到一個statement 句柄,用這個句柄執行查詢,並提供數據值填充佔位符:
       sth = dbh.prepare("SELECT * FROM people WHERE name = ?")
       sth.execute("Na'il")
       sth.fetch do |row|
           printf "ID: %d, Name: %s, Height: %.1f/n", row[0], row[1], row[2]
       end
       sth.finish
    
  • 如果你不用 prepare那麼execute方法的第一個參數就是要執行的語句,後面的參數是要填充用的數據值:
       sth = dbh.execute("SELECT * FROM people WHERE name = ?", "Na'il")
       sth.fetch do |row|
           printf "ID: %d, Name: %s, Height: %.1f/n", row[0], row[1], row[2]
       end
       sth.finish
    
其它的驅動也許需要用不同的佔位符,比如你可能需要寫 :name:n  來指明是按名稱還是按位置來對應。

方法quote 能將一個值中的特殊字符處理、轉義等,並返回這個結果。這適用於產生sql語句以供別的程序使用,比如,你想將上面的people.txt文件的內容轉化爲能在mysql命令行裏執行的一組insert語句,只需要如下程序:

   # read each line from file, split into values, and write INSERT statement
   f = File.open("people.txt", "r")
   f.each_line do |line|
       name, height = line.chomp.split("/t")
       printf "INSERT INTO people (id, name, height) VALUES(%s, %s, %s);/n",
               dbh.quote(nil), dbh.quote(name), dbh.quote(height)
   end
   f.close

查詢元數據 (Metadata) 


對於不需要返回結果的語句,比如insert,delete等,do方法返回insert或者delete的行數。

對於返回結果的查詢,比如select,你可以在execute方法之後用statement句柄取得返回的行和列的個數,以及各列的信息:

  • 行數和列數不能直接得到,爲了得到行數,你可以循環處理每一行的時候進行計數,或者將結果放到一個數據結構裏,然後看看這個數據結構有多少個元素。要想得到返回的列的個數,你可以從sth.column_names.size得到。
  • 方法column_info 返回各列的詳細信息。
下面例子說明了如何從一個查詢得到metadata:
   sth = dbh.execute(query)
   puts "Query: " + query
   if sth.column_names.size == 0 then
       puts "Query has no result set"
       printf "Number of rows affected: %d/n", sth.rows
   else
       puts "Query has a result set"
       rows = sth.fetch_all
       printf "Number of rows: %d/n", rows.size
       printf "Number of columns: %d/n", sth.column_names.size
       sth.column_info.each_with_index do |info, i|
           printf "--- Column %d (%s) ---/n", i, info.name
           printf "precision:  %s/n", info.precision
           printf "scale:      %s/n", info.scale
       end
   end
   sth.finish
注意:本文檔的早期版本中說你可以從sth.rows得到返回的行數,現在已經不支持了。(儘管現在在mysql驅動中還可以用,但是你不應該在依賴這個函數了)

接受代碼塊的方法(Methods That Take Code Blocks)


一些能產生句柄的方法可以用來在block中調用,用這種方法時,它們將句柄作爲參數提供給block,並且在塊結束後自動銷燬這些句柄。

  • DBI.connect 產生一個數據庫句柄(database handle),在塊結束後會(自動)調用disconnect。
  • dbh.prepare 產生一個statement句柄(statement handle),在塊結束後,會自動調用finish方法,在塊內部,你必須調用execute方法來執行語句。
  • dbh.execute 也和上面類似,但是你不需要在塊內部調用execute方法,statement會自動執行。
下面的例子說明了上面的三個問題:
   # connect can take a code block, passes the database handle to it,
   # and automatically disconnects the handle at the end of the block
   DBI.connect("dbi:Mysql:test:localhost", "testuser", "testpass") do |dbh|
       # prepare can take a code block, passes the statement handle
       # to it, and automatically calls finish at the end of the block
       dbh.prepare("SHOW DATABASES") do |sth|
           sth.execute
           puts "Databases: " + sth.fetch_all.join(", ")
       end
       # execute can take a code block, passes the statement handle
       # to it, and automatically calls finish at the end of the block
       dbh.execute("SHOW DATABASES") do |sth|
           puts "Databases: " + sth.fetch_all.join(", ")
       end
   end
此外還有一個 transaction 方法可以接收一個塊,將在下面的“事務處理支持”中討論。

再論連接數據庫


前面討論過的simple.rb 腳本用DBI 的connect方法連接數據庫服務器:

   dbh = DBI.connect("dbi:Mysql:test:localhost", "testuser", "testpass")
connect的第一個參數十DSN,它指明瞭要連接類型,後面的參數是用戶名和密碼。

 DSN 可以是下面的任何格式的一種:

   dbi:driver_name
   dbi:driver_name:db_name:host_name
   dbi:driver_name:key=val;key=val...
 DSN總是以dbi或者DBI(而不能既有大寫又有小寫的字母)和驅動名稱開頭,對MySql來說,驅動名稱是Mysql,對於其他的驅動,需要指定對應的正確的名字。

DSN中必須有dbi (或 DBI) ,如果在驅動後面沒有其他信息,那麼驅動會嘗試用默認得數據庫和機器名連接數據庫。而mysql要求必須指定數據庫名,所以上面的第一種寫法不能用於mysql,必須用其他的寫法。第二種寫法需要兩個值,一個數據庫名,一個機器名,兩個值用冒號分開。第三種格式允許用 param=value 格式指定一系列的參數,參數之間用分號分割,比如,下面三種寫法完全等同:

   dbi:Mysql:test:localhost
   dbi:Mysql:host=localhost;database=test
   dbi:Mysql:database=test;host=localhost
在 DSN 語法中使用 param=value 格式比較靈活,各個參數的位置可以隨意設置。而且可以設置一些針對不同驅動的特有的參數,就是說可以在它接收的參數方面進行擴展。比如Mysql,除了host和database參數,還可以設置port,socket,flag等參數。(這些參數對應於ruby mysql 模塊的real_connect方法中的各個參數,而DBD::Mysql也是基於這個Ruby Mysql模塊的)

 

錯誤處理和調試


如果一個DBI方法是白了,將拋出一個異常。DBI方法可以拋出幾種異常,但是和數據庫相關的方法一般拋出DatabaseError異常,這種異常的對象有三個屬性,err,errstr和state。DBI的文檔沒有說這三個屬性是什麼意思,但是看起來它們分別表示錯誤編號,一個字符串型的錯誤描述和一些“標準”的錯誤代碼。目前MySQL驅動只支持errstr,但很容易用補丁使它也支持err屬性。假定這兩個屬性都可用,那麼下面方法說明了如何得到這些值:
   rescue DBI::DatabaseError => e
       puts "An error occurred"
       puts "Error code: #{e.err}"
       puts "Error message: #{e.errstr}"
爲了得到你的語句執行時的調試信息,可以使用跟蹤(tracing)。要想這樣,首先你要載入dbi/trace模塊:
   require "dbi/trace"
模塊 dbi/trace 默認沒有包括在dbi模塊中,因爲這需要0.3.3以上版本的AspectR模塊,這個模塊可能在你的機器上並不存在。

dbi/trace 模塊提供了一個trace方法,可以用來控制跟蹤模式和輸出目標:

   trace(mode, destination)

mode 值爲0(off),1,2,3,默認值爲2; destination 是一個IO對象,默認爲STDERR。

trace 可以作爲一個類方法調用,這樣隨後創建的句柄都可以使用;或者作爲一個單獨的驅動,數據庫,statement 句柄的對象方法,任何繼承這些對象的子類都可以繼承這些跟蹤設置。比如,比如,你允許一個數據庫句柄進行跟蹤,從這個句柄創建的statement句柄也具備同樣的跟蹤設置。

事務處理支持


DBI提供了事務支持,但是怎樣支持取決於你的底層數據庫和DBD層數據庫驅動的實現情況。比如Mysql驅動,在DBI 0.0.19之前都沒有提供,所以你必須使用statement的自動提交功能來達到同樣的目的,比如:
   dbh.do("SET AUTOCOMMIT=0")
   dbh.do("BEGIN")
   ... statements that make up the transaction ...
   dbh.do("COMMIT")
對於 DBI 0.0.19 和更高版本,你可以使用mysql的事務控制,可以設置數據庫句柄來設置是否自動提交:
   dbh['AutoCommit'] = true
   dbh['AutoCommit'] = false
當自動提交被禁止之後,你有兩種方法來實現事務控制。下面的例子說明了這兩種方法,一個表account,要在兩個人時間的基金轉帳中實現事務性操作:
  • 首先是用 DBI的 commitrollback 方法顯示的提交或者取消事務:
       dbh['AutoCommit'] = false
       begin
           dbh.do("UPDATE account SET balance = balance - 50
                   WHERE name = 'bill'")
           dbh.do("UPDATE account SET balance = balance + 50
                   WHERE name = 'bob'")
           dbh.commit
       rescue
           puts "transaction failed"
           dbh.rollback
       end
    
  • 第二種方法用了transaction方法,這種方法很簡單,它接受了一個要求事務操作的處理塊,transaction方法執行這個塊,然後根據這個塊執行結果是成功還是失敗自動執行commit或者rollback。
       dbh['AutoCommit'] = false
       dbh.transaction do |dbh|
           dbh.do("UPDATE account SET balance = balance - 50
                   WHERE name = 'bill'")
           dbh.do("UPDATE account SET balance = balance + 50
                   WHERE name = 'bob'")
       end
    

使用不同驅動特有的功能(Driver-Specific Capabilities)


DBI提供了一個func方法,可以執行不同數據庫驅動特有的功能,比如,mysql C API提供了mysq_insert_id()方法,這個方法返回AUTO_INCREMENT 的最新值。Ruby Mysql模塊提供了一個綁定到這個函數的函數:數據庫句柄的insert_id 方法。這個方法是在DBD::Mysql中提供的,使得你可以通過DBI訪問。

  func 的第一個參數是你想執行的數據庫特有的方法的名稱,後面的參數是這個數據庫特有方法的參數,如果沒有參數,可以不填。insert_id沒有參數,所以要想訪問最新的AUTO_INCREMENT 值,可以這樣:

   dbh.do("INSERT INTO people (name,height) VALUES('Mike',70.5)")
   id = dbh.func(:insert_id)
   puts "ID for new record is: " + id.to_s
  DBD::Mysql 提供的其它方法包括:
   dbh.func(:createdb, db_name) 創建數據庫
   dbh.func(:dropdb, db_name)   刪除數據庫
   dbh.func(:reload)            重新加載(reload)
   dbh.func(:shutdown)          關閉數據庫
注意的是,只有你的mysql版本在4以上,創建數據庫和刪除數據庫的功能纔可以使用。

有些時候,使用數據庫特有的方法能有特別的有點,即使按通常的其他方法也能達到同樣的作用。比如,DBD::Mysql 的insert_id方法的功能和執行查詢語句“SELECT LAST_INSERT_ID()”一樣,都返回同一個值,但是insert_id更有效,因爲它把這個值保存在了客戶端,再次需要時不用重複執行查找。每次有新的插入之後,這個值都會改變,所以你必須重新得到這個AUTO_INCREMENT 值。與此相對,LAST_INSERT_ID() 的結果保存在服務器上,所以是持久穩固的,它不會因爲別的查詢語句執行而改變。

一些有用的DBI模塊和工具


模塊DBI::Utils 包含了其他一些有趣的方法(包括子模塊中的方法):
  • DBI::Utils::measure 接受一個block,然後計算執行這個block需要多長時間:
       elapsed = DBI::Utils::measure do
           dbh.do(query)
       end
       puts "Query: " + query
       puts "Elapsed time: " + elapsed.to_s
    
  • 模塊 DBI::Utils::TableFormatter 中的方法ascii 用來打印一個結果集(包括表頭),第一個參數是一個包含列名的數組,第二個參數是一個row對象的數組。爲了打印表people的內容,可以用如下代碼:
       sth = dbh.execute("SELECT * FROM people")
       rows = sth.fetch_all
       col_names = sth.column_names
       sth.finish
       DBI::Utils::TableFormatter.ascii(col_names, rows)
    
    輸出結果如下:
       +----+---------+--------+
       | id | name    | height |
       +----+---------+--------+
       | 1  | Wanda   | 62.5   |
       | 2  | Robert  | 75.0   |
       | 3  | Phillip | 71.5   |
       | 4  | Sarah   | 68.0   |
       +----+---------+--------+
    
  • 模塊DBI::Utils::XMLFormatter 包含rowtable方法,用來用xml格式輸出一行或者整個結果集的數據。這使得從數據庫中生成xml文檔變得方便簡單,下面例子演示了table方法:
       DBI::Utils::XMLFormatter.table(dbh.select_all("SELECT * FROM people"))
    
    輸出結果如下:
       <?xml version="1.0" encoding="UTF-8" ?>
       <rows>
       <row>
         <id>1</id>
         <name>Wanda</name>
         <height>62.5</height>
       </row>
       <row>
         <id>2</id>
         <name>Robert</name>
         <height>75.0</height>
       </row>
       <row>
         <id>3</id>
         <name>Phillip</name>
         <height>71.5</height>
       </row>
       <row>
         <id>4</id>
         <name>Sarah</name>
         <height>68.0</height>
       </row>
       </rows>
    
方法  asciitable 支持更多的參數以提供對結果的更多控制和更多的格式和輸出方式,可以參看這個模塊的源代碼獲取更多信息。

資源


本文用到的腳本可以從下面的地址下載:

   http://www.kitebird.com/articles/

那裏你也可以找到另一篇文章 "使用 Ruby MySQL 模塊" ,這篇文章討論了作爲DBD:Mysql的基礎的Ruby Mysql模塊。

你會發現下面這些額外資源對你很好的使用Ruby DBI很有幫助:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章