九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
ruby操作常用數(shù)據(jù)庫(kù)

使用Ruby DBI模塊

原著 Paul DuBois   paul@kitebird.com

翻譯: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程序訪問數(shù)據(jù)庫(kù)提供了一個(gè)與數(shù)據(jù)庫(kù)無(wú)關(guān)的接口,就像perl的DBI模塊一樣。這篇文章將講述如何編寫基于DBI的ruby程序。這篇文章是對(duì)DBI規(guī)范文檔(specification documents)的補(bǔ)充,而不是要替代規(guī)范文檔,更多的信息請(qǐng)參見“資源”一節(jié)。

Ruby的DBI 模塊架構(gòu)分為兩層:

  • 數(shù)據(jù)庫(kù)接口層(database interface DBI)。這層是與數(shù)據(jù)庫(kù)無(wú)關(guān)的,它提供一些與你具體使用的數(shù)據(jù)庫(kù)無(wú)關(guān)的通用的訪問方法。。
  • 數(shù)據(jù)庫(kù)驅(qū)動(dòng)層(database driver DBD)。這一層是與數(shù)據(jù)庫(kù)相關(guān)的,不同的驅(qū)動(dòng)用來(lái)訪問不同的數(shù)據(jù)庫(kù)。一個(gè)驅(qū)動(dòng)用來(lái)訪問mysql,另一個(gè)用來(lái)訪問postgresql,每一個(gè)具體的數(shù)據(jù)庫(kù)都有不同的驅(qū)動(dòng)。每個(gè)驅(qū)動(dòng)解釋DBI層傳送的請(qǐng)求,并轉(zhuǎn)換成對(duì)應(yīng)于具體數(shù)據(jù)庫(kù)的請(qǐng)求,發(fā)送到數(shù)據(jù)庫(kù)。

本文的例子用到的數(shù)據(jù)庫(kù)都是mysql的,但多數(shù)也可以適用其他數(shù)據(jù)庫(kù)驅(qū)動(dòng)。

準(zhǔn)備


Ruby DBI模塊包括了實(shí)現(xiàn)一般DBI的代碼,和一些DBD層的驅(qū)動(dòng),很多這些驅(qū)動(dòng)需要你安裝額外的軟件。比如,用于Mysql的驅(qū)動(dòng)使用ruby寫成,與ruby mysql模塊綁定,而ruby mysql驅(qū)動(dòng)是c語(yǔ)言寫的,幫定了mysql 的c語(yǔ)言 客戶端API。這就是說(shuō),你要是想用DBI訪問MySql數(shù)據(jù)庫(kù),ruby mysql模塊和C API這兩者都需要安裝。更多關(guān)于ruby mysql 模塊的信息,參見“資源”一節(jié)。這里我們假定你已經(jīng)安裝了ruby mysql,并且可以用于DBI。

安裝


一旦你滿足了前面的條件,就可以安裝Ruby DBI模塊,可以從這里取得:

   http://ruby-dbi.sourceforge.net/

DBI模塊以壓縮的tar格式發(fā)布,下載之后應(yīng)該解壓縮,比如,現(xiàn)在版本是0.0.19,如下即可解壓縮:

   % tar zxf ruby-dbi-all-0.0.19.tar.gz   % gunzip < ruby-dbi-all-0.0.19.tar.gz | tar xf -

解壓縮之后,進(jìn)入軟件包的頂層目錄下,用setup.rb腳本進(jìn)行配置。一般的配置命令都像這樣,在config后面沒有參數(shù):

   % ruby setup.rb config

這條命令設(shè)置了默認(rèn)安裝所有的驅(qū)動(dòng),更有效的辦法是在剛才的config 后面加上--with參數(shù),指定需要安裝的部分。比如,為了配置只安裝主DBI模塊和MYSQL  DBD 驅(qū)動(dòng),運(yùn)行下面命令:

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

配置完要安裝的軟件之后,就可以build和安裝了:

   % ruby setup.rb setup   % ruby setup.rb install

運(yùn)行install需要root權(quán)限。

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

  • "DBI module" 指的是包括DBI層和DBD層都在內(nèi)的集合,除非上下文說(shuō)明了這層是獨(dú)立于數(shù)據(jù)庫(kù)。
  • "DBD::Mysql" 指的是用于DBI的特定于MySQL的數(shù)據(jù)庫(kù)驅(qū)動(dòng)。
  • "Ruby MySQL 模塊" 指的是用于建造DBD::Mysql的基礎(chǔ)模塊。

一個(gè)簡(jiǎn)單的DBI腳本


安裝完ruby DBI模塊之后,你就可以在你的Ruby程序中訪問MYSQL數(shù)據(jù)庫(kù)了。假設(shè)我們的數(shù)據(jù)庫(kù)在本機(jī)運(yùn)行,即localhost,數(shù)據(jù)庫(kù)名為test,通過(guò)一個(gè)用戶名為testuser,密碼是testpass的用戶訪問。我們可以用root登陸到mysql程序,然后執(zhí)行下列命令建立這樣的一個(gè)用戶:

   mysql> GRANT ALL ON test.* TO 'testuser'@'localhost' IDENTIFIED BY 'testpass';

如果test數(shù)據(jù)庫(kù)不存在,用下面的命令創(chuàng)建它:

   mysql> CREATE DATABASE test;

如果你想用不同的數(shù)據(jù)庫(kù),服務(wù)器,用戶和密碼的話,只需要將例子里對(duì)應(yīng)的值換成你自己的就行了。

下面這個(gè)腳本, simple.rb, 是一個(gè)很短的DBI程序,它先連接的數(shù)據(jù)庫(kù),然后查詢了數(shù)據(jù)庫(kù)的版本,并顯示出來(lái),然后斷開連接。你可以從“資源”里提供的鏈接下載這段代碼,或者把它拷貝到文本編輯器中:

# 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 展現(xiàn)了DBI最基本的一些概念,下面的討論將會(huì)講述他是如何工作的,然后更后面還要講述DBI的其他一些方面。

simple.rb以一行require 開始,把DBI模塊引入近來(lái);沒有這一行的話,DBI方法將會(huì)出錯(cuò),后面的代碼包括在一個(gè) begin/rescue/ensure 結(jié)構(gòu)中:

  • begin 部分處理了所有的數(shù)據(jù)庫(kù)請(qǐng)求。
  • rescue 部分用來(lái)處理出錯(cuò)信息,它將獲取出錯(cuò)信息,并顯示出來(lái)。
  • ensure 塊確保程序不管出錯(cuò)與否,最后都將關(guān)閉數(shù)據(jù)庫(kù)連接。

方法connect 用來(lái)和數(shù)據(jù)庫(kù)服務(wù)器建立一個(gè)連接,并返回這個(gè)連接。第一個(gè)參數(shù)是數(shù)據(jù)源名(data source name DSN),它指定了驅(qū)動(dòng)名稱(Mysql用于MySql服務(wù)器),默認(rèn)得數(shù)據(jù)庫(kù)名和服務(wù)器的機(jī)器名,第二、三個(gè)參數(shù)是用戶和密碼。還有其他的DSN寫法, 將在后面“再論連接數(shù)據(jù)庫(kù)”中說(shuō)明。

simple.rb 用數(shù)據(jù)庫(kù)句柄(database handle)調(diào)用方法select_one, 這個(gè)方法向服務(wù)器發(fā)送一個(gè)查詢語(yǔ)句,并且將結(jié)果集的第一行作為數(shù)組返回給調(diào)用者?!?tt>SELECT VERSION() ”返回返回單個(gè)值,所以版本信息將存在row[0]中,這是這個(gè)數(shù)組的第一個(gè)也是唯一一個(gè)元素。運(yùn)行這個(gè)程序,結(jié)果像這樣:

   % ruby simple.rb   Server version: 4.0.13-log

如果出錯(cuò),會(huì)導(dǎo)致拋出異常,異常可能各種各樣,但多數(shù)都屬于數(shù)據(jù)庫(kù)錯(cuò)誤,多為DatabaseError 異常,這種異常對(duì)象包括err和errstr屬性,err是錯(cuò)誤編號(hào),errstr是錯(cuò)誤消息。simple.rb得到這些異常的值并打印它們,但是忽略了其他的異常,這時(shí)候如果出現(xiàn)了其他異常,則將會(huì)拋給ruby執(zhí)行環(huán)境。

simple.rb 用disconnect方法來(lái)斷開與數(shù)據(jù)庫(kù)的連接,這在ensure里執(zhí)行,這樣就使得不管出錯(cuò)與否,數(shù)據(jù)庫(kù)連接都會(huì)被斷開。

處理查詢


Ruby DBI 提供了很多方法用來(lái)執(zhí)行查詢語(yǔ)句。這里將討論這中間的一部分,但還有其他的。

多數(shù)的例子都用到了表people,它的結(jié)構(gòu)如下:

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)   );

處理不返回結(jié)果集的查詢


如果一個(gè)語(yǔ)句不需要返回結(jié)果,可以用數(shù)據(jù)庫(kù)句柄的do方法,這個(gè)方法的參數(shù)為要執(zhí)行的sql語(yǔ)句,返回受影響的行數(shù)。下面的例子創(chuàng)建了表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語(yǔ)句返回了一個(gè)值,即插入的行數(shù),并把它打印了出來(lái)。

處理返回結(jié)果集的查詢


像select和show這樣的語(yǔ)句是要返回行記錄的,處理這樣的語(yǔ)句,要先向服務(wù)器提交查詢,處理查詢產(chǎn)生的每條記錄,然后把結(jié)果集銷毀。

一種辦法是調(diào)用prepare產(chǎn)生一個(gè)statement 句柄,用這個(gè)句柄來(lái)執(zhí)行查詢,取回結(jié)果,然后釋放結(jié)果集:

   sth = dbh.prepare(statement)   sth.execute   ... fetch rows ...   sth.finish

或者直接把語(yǔ)句發(fā)送給數(shù)據(jù)庫(kù)連接句柄去執(zhí)行而不用調(diào)用prepare:

   sth = dbh.execute(statement)   ... fetch rows ...   sth.finish

同樣也有很多方法從執(zhí)行完的語(yǔ)句取得結(jié)果,可以在一個(gè)循環(huán)里調(diào)用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 也可以用作一個(gè) iterator來(lái)用, 也用each.方法。下面的兩個(gè)是一樣的作用:

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 都產(chǎn)生了 DBI::Row 對(duì)象, 這個(gè)對(duì)象提供了訪問他們內(nèi)容的方法:

  • 可以用by_indexby_field 來(lái)通過(guò)順序或者名字訪問字段值:
       val = row.by_index(2)   val = row.by_field("height")
  • 字段值也可以將row對(duì)象當(dāng)成數(shù)組來(lái)取得:
       val = row[2]   val = row["height"]
  • 迭代方法 each_with_name 生成每個(gè)字段名和它們的值:
        
    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 對(duì)象提供了一個(gè)方法 column_names 來(lái)得到一個(gè)包含每個(gè)字段名的數(shù)組。  field_namescolumn_names的別名。

其他的返回行數(shù)據(jù)的方法包括fetch_array和fetch_hash,他們不返回DBI::Row對(duì)象,而是將下一行數(shù)據(jù)作為數(shù)組或者哈希返回, 如果已經(jīng)到結(jié)果集的最后的話,也會(huì)返回nil。fetch_hash返回哈希結(jié)構(gòu),由列名作為key,而列的值作為這個(gè)key對(duì)應(yīng)的值。這兩個(gè)方法可以獨(dú)立使用,也可以在迭代中使用。下面例子用了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

你也可以不用依照 “查詢--取結(jié)果--完成”這種順序來(lái)執(zhí)行你的語(yǔ)句,數(shù)據(jù)庫(kù)句柄可以一次取回所有的結(jié)果:

   row = dbh.select_one(statement)   rows = dbh.select_all(statement)

select_one 執(zhí)行一個(gè)查詢,然后將結(jié)果的第一行作為一個(gè)數(shù)組返回,或者返回nil,如果沒有匹配記錄的話。select_all 返回一個(gè) DBI::Row 的數(shù)組,(你可以用前面討論過(guò)得方法訪問里面的內(nèi)容)。如果沒有匹配結(jié)果,則返回空數(shù)組。注意不是nil。

  MySQL 驅(qū)動(dòng)會(huì)檢查返回的結(jié)果集中的元數(shù)據(jù)(metadata),然后強(qiáng)制將這個(gè)字段的的值變?yōu)閷?duì)應(yīng)的Ruby類型(比如,從people取得的id,name,height字段的值將會(huì)被轉(zhuǎn)變?yōu)镕ixnum,String和Float對(duì)象)。但是,如果一個(gè)列的值為NULL,則用nil來(lái)表示,并且它的類型為NilClass。還有就是這不是DBI規(guī)格說(shuō)明書的硬性規(guī)定,所以有的驅(qū)動(dòng)可能不會(huì)做這樣的工作。

引用,占位符(placeholder)和參數(shù)綁定


Ruby DBI提供了占位符機(jī)制,使得你可以不用在查詢語(yǔ)句中把數(shù)據(jù)值的字面值寫到里面,而是用一些特殊的符號(hào)標(biāo)記數(shù)據(jù)的位置,當(dāng)你真的要執(zhí)行的時(shí)候,用真實(shí)的數(shù)據(jù)值填充占位符的位置。DBI會(huì)用數(shù)據(jù)值替換占位符,完成對(duì)字符串等加引號(hào),特殊字符的轉(zhuǎn)義(如果需要的話)等,而不必你自己去做,而且占位符機(jī)制能很好的處理NULL值,你只需要提供一個(gè)nil值,它會(huì)自動(dòng)被換成NULL放到查詢中。

下面例子解釋了它是如何工作的。加入你想向people表里插入一條記錄,這個(gè)人的名字叫Na'il,這個(gè)名字包括一個(gè)單引號(hào),他的身高是76英寸。在查詢語(yǔ)句中,用?來(lái)作為插入值的占位符,不需要引號(hào)括起來(lái),然后將實(shí)際要插入的值作為do的參數(shù),如下:

   dbh.do("INSERT INTO people (id, name, height) VALUES(?, ?, ?)",           nil, "Na'il", 76)

這條語(yǔ)句發(fā)送給數(shù)據(jù)庫(kù)的語(yǔ)句像這樣:

   INSERT INTO people (id,name,height) VALUES(NULL,'Na\'il',76)

這更適合于你要多次執(zhí)行一個(gè)查詢,你可以先生成一個(gè)預(yù)處理語(yǔ)句語(yǔ)句,然后每次用數(shù)據(jù)值填充去執(zhí)行。假如要導(dǎo)入的數(shù)據(jù)存在文本文件people.txt里面,每一行了用tab分割,由name,height兩列組成,下面的代碼演示了如何從數(shù)據(jù)文件讀取數(shù)據(jù),然后執(zhí)行insert語(yǔ)句將每一行插入數(shù)據(jù)庫(kù):

   # 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

生成一個(gè)預(yù)處理語(yǔ)句,然后在循環(huán)中多次執(zhí)行它,比用循環(huán)來(lái)直接執(zhí)行有效多了,主要是因?yàn)閿?shù)據(jù)庫(kù)能為預(yù)處理語(yǔ)句生成一個(gè)執(zhí)行計(jì)劃,以后每次執(zhí)行都會(huì)用這個(gè)執(zhí)行計(jì)劃來(lái)執(zhí)行,提高了效率。當(dāng)然目前mysql還不支持這個(gè)功能,oracle支持。

如果想用占位符的方法執(zhí)行select語(yǔ)句,你應(yīng)該先考慮一下是否用預(yù)處理語(yǔ)句:

  • 如果你用prepare 方法得到一個(gè)statement 句柄,用這個(gè)句柄執(zhí)行查詢,并提供數(shù)據(jù)值填充占位符:
       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方法的第一個(gè)參數(shù)就是要執(zhí)行的語(yǔ)句,后面的參數(shù)是要填充用的數(shù)據(jù)值:
       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

其它的驅(qū)動(dòng)也許需要用不同的占位符,比如你可能需要寫 :name:n  來(lái)指明是按名稱還是按位置來(lái)對(duì)應(yīng)。

方法quote 能將一個(gè)值中的特殊字符處理、轉(zhuǎn)義等,并返回這個(gè)結(jié)果。這適用于產(chǎn)生sql語(yǔ)句以供別的程序使用,比如,你想將上面的people.txt文件的內(nèi)容轉(zhuǎn)化為能在mysql命令行里執(zhí)行的一組insert語(yǔ)句,只需要如下程序:

   # 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

查詢?cè)獢?shù)據(jù) (Metadata) 


對(duì)于不需要返回結(jié)果的語(yǔ)句,比如insert,delete等,do方法返回insert或者delete的行數(shù)。

對(duì)于返回結(jié)果的查詢,比如select,你可以在execute方法之后用statement句柄取得返回的行和列的個(gè)數(shù),以及各列的信息:

  • 行數(shù)和列數(shù)不能直接得到,為了得到行數(shù),你可以循環(huán)處理每一行的時(shí)候進(jìn)行計(jì)數(shù),或者將結(jié)果放到一個(gè)數(shù)據(jù)結(jié)構(gòu)里,然后看看這個(gè)數(shù)據(jù)結(jié)構(gòu)有多少個(gè)元素。要想得到返回的列的個(gè)數(shù),你可以從sth.column_names.size得到。
  • 方法column_info 返回各列的詳細(xì)信息。

下面例子說(shuō)明了如何從一個(gè)查詢得到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

注意:本文檔的早期版本中說(shuō)你可以從sth.rows得到返回的行數(shù),現(xiàn)在已經(jīng)不支持了。(盡管現(xiàn)在在mysql驅(qū)動(dòng)中還可以用,但是你不應(yīng)該在依賴這個(gè)函數(shù)了)

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


一些能產(chǎn)生句柄的方法可以用來(lái)在block中調(diào)用,用這種方法時(shí),它們將句柄作為參數(shù)提供給block,并且在塊結(jié)束后自動(dòng)銷毀這些句柄。

  • DBI.connect 產(chǎn)生一個(gè)數(shù)據(jù)庫(kù)句柄(database handle),在塊結(jié)束后會(huì)(自動(dòng))調(diào)用disconnect。
  • dbh.prepare 產(chǎn)生一個(gè)statement句柄(statement handle),在塊結(jié)束后,會(huì)自動(dòng)調(diào)用finish方法,在塊內(nèi)部,你必須調(diào)用execute方法來(lái)執(zhí)行語(yǔ)句。
  • dbh.execute 也和上面類似,但是你不需要在塊內(nèi)部調(diào)用execute方法,statement會(huì)自動(dòng)執(zhí)行。

下面的例子說(shuō)明了上面的三個(gè)問題:

   # 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

此外還有一個(gè) transaction 方法可以接收一個(gè)塊,將在下面的“事務(wù)處理支持”中討論。

再論連接數(shù)據(jù)庫(kù)


前面討論過(guò)的simple.rb 腳本用DBI 的connect方法連接數(shù)據(jù)庫(kù)服務(wù)器:

   dbh = DBI.connect("dbi:Mysql:test:localhost", "testuser", "testpass")

connect的第一個(gè)參數(shù)十DSN,它指明了要連接類型,后面的參數(shù)是用戶名和密碼。

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

   dbi:driver_name   dbi:driver_name:db_name:host_name   dbi:driver_name:key=val;key=val...

 DSN總是以dbi或者DBI(而不能既有大寫又有小寫的字母)和驅(qū)動(dòng)名稱開頭,對(duì)MySql來(lái)說(shuō),驅(qū)動(dòng)名稱是Mysql,對(duì)于其他的驅(qū)動(dòng),需要指定對(duì)應(yīng)的正確的名字。

DSN中必須有dbi (或 DBI) ,如果在驅(qū)動(dòng)后面沒有其他信息,那么驅(qū)動(dòng)會(huì)嘗試用默認(rèn)得數(shù)據(jù)庫(kù)和機(jī)器名連接數(shù)據(jù)庫(kù)。而mysql要求必須指定數(shù)據(jù)庫(kù)名,所以上面的第一種寫法不能用于mysql,必須用其他的寫法。第二種寫法需要兩個(gè)值,一個(gè)數(shù)據(jù)庫(kù)名,一個(gè)機(jī)器名,兩個(gè)值用冒號(hào)分開。第三種格式允許用 param=value 格式指定一系列的參數(shù),參數(shù)之間用分號(hào)分割,比如,下面三種寫法完全等同:

   dbi:Mysql:test:localhost   dbi:Mysql:host=localhost;database=test   dbi:Mysql:database=test;host=localhost

在 DSN 語(yǔ)法中使用 param=value 格式比較靈活,各個(gè)參數(shù)的位置可以隨意設(shè)置。而且可以設(shè)置一些針對(duì)不同驅(qū)動(dòng)的特有的參數(shù),就是說(shuō)可以在它接收的參數(shù)方面進(jìn)行擴(kuò)展。比如Mysql,除了host和database參數(shù),還可以設(shè)置port,socket,flag等參數(shù)。(這些參數(shù)對(duì)應(yīng)于ruby mysql 模塊的real_connect方法中的各個(gè)參數(shù),而DBD::Mysql也是基于這個(gè)Ruby Mysql模塊的)

 

錯(cuò)誤處理和調(diào)試


如果一個(gè)DBI方法是白了,將拋出一個(gè)異常。DBI方法可以拋出幾種異常,但是和數(shù)據(jù)庫(kù)相關(guān)的方法一般拋出DatabaseError異常,這種異常的對(duì)象有三個(gè)屬性,err,errstr和state。DBI的文檔沒有說(shuō)這三個(gè)屬性是什么意思,但是看起來(lái)它們分別表示錯(cuò)誤編號(hào),一個(gè)字符串型的錯(cuò)誤描述和一些“標(biāo)準(zhǔn)”的錯(cuò)誤代碼。目前MySQL驅(qū)動(dòng)只支持errstr,但很容易用補(bǔ)丁使它也支持err屬性。假定這兩個(gè)屬性都可用,那么下面方法說(shuō)明了如何得到這些值:

   rescue DBI::DatabaseError => e       puts "An error occurred"       puts "Error code: #{e.err}"       puts "Error message: #{e.errstr}"

為了得到你的語(yǔ)句執(zhí)行時(shí)的調(diào)試信息,可以使用跟蹤(tracing)。要想這樣,首先你要載入dbi/trace模塊:

   require "dbi/trace"

模塊 dbi/trace 默認(rèn)沒有包括在dbi模塊中,因?yàn)檫@需要0.3.3以上版本的AspectR模塊,這個(gè)模塊可能在你的機(jī)器上并不存在。

dbi/trace 模塊提供了一個(gè)trace方法,可以用來(lái)控制跟蹤模式和輸出目標(biāo):

   trace(mode, destination)

mode 值為0(off),1,2,3,默認(rèn)值為2; destination 是一個(gè)IO對(duì)象,默認(rèn)為STDERR。

trace 可以作為一個(gè)類方法調(diào)用,這樣隨后創(chuàng)建的句柄都可以使用;或者作為一個(gè)單獨(dú)的驅(qū)動(dòng),數(shù)據(jù)庫(kù),statement 句柄的對(duì)象方法,任何繼承這些對(duì)象的子類都可以繼承這些跟蹤設(shè)置。比如,比如,你允許一個(gè)數(shù)據(jù)庫(kù)句柄進(jìn)行跟蹤,從這個(gè)句柄創(chuàng)建的statement句柄也具備同樣的跟蹤設(shè)置。

事務(wù)處理支持


DBI提供了事務(wù)支持,但是怎樣支持取決于你的底層數(shù)據(jù)庫(kù)和DBD層數(shù)據(jù)庫(kù)驅(qū)動(dòng)的實(shí)現(xiàn)情況。比如Mysql驅(qū)動(dòng),在DBI 0.0.19之前都沒有提供,所以你必須使用statement的自動(dòng)提交功能來(lái)達(dá)到同樣的目的,比如:

   dbh.do("SET AUTOCOMMIT=0")   dbh.do("BEGIN")   ... statements that make up the transaction ...   dbh.do("COMMIT")

對(duì)于 DBI 0.0.19 和更高版本,你可以使用mysql的事務(wù)控制,可以設(shè)置數(shù)據(jù)庫(kù)句柄來(lái)設(shè)置是否自動(dòng)提交:

   dbh['AutoCommit'] = true   dbh['AutoCommit'] = false

當(dāng)自動(dòng)提交被禁止之后,你有兩種方法來(lái)實(shí)現(xiàn)事務(wù)控制。下面的例子說(shuō)明了這兩種方法,一個(gè)表account,要在兩個(gè)人時(shí)間的基金轉(zhuǎn)帳中實(shí)現(xiàn)事務(wù)性操作:

  • 首先是用 DBI的 commitrollback 方法顯示的提交或者取消事務(wù):
       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方法,這種方法很簡(jiǎn)單,它接受了一個(gè)要求事務(wù)操作的處理塊,transaction方法執(zhí)行這個(gè)塊,然后根據(jù)這個(gè)塊執(zhí)行結(jié)果是成功還是失敗自動(dòng)執(zhí)行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

使用不同驅(qū)動(dòng)特有的功能(Driver-Specific Capabilities)


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

  func 的第一個(gè)參數(shù)是你想執(zhí)行的數(shù)據(jù)庫(kù)特有的方法的名稱,后面的參數(shù)是這個(gè)數(shù)據(jù)庫(kù)特有方法的參數(shù),如果沒有參數(shù),可以不填。insert_id沒有參數(shù),所以要想訪問最新的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) 創(chuàng)建數(shù)據(jù)庫(kù)   dbh.func(:dropdb, db_name)   刪除數(shù)據(jù)庫(kù)   dbh.func(:reload)            重新加載(reload)   dbh.func(:shutdown)          關(guān)閉數(shù)據(jù)庫(kù)

注意的是,只有你的mysql版本在4以上,創(chuàng)建數(shù)據(jù)庫(kù)和刪除數(shù)據(jù)庫(kù)的功能才可以使用。

有些時(shí)候,使用數(shù)據(jù)庫(kù)特有的方法能有特別的有點(diǎn),即使按通常的其他方法也能達(dá)到同樣的作用。比如,DBD::Mysql 的insert_id方法的功能和執(zhí)行查詢語(yǔ)句“SELECT LAST_INSERT_ID()”一樣,都返回同一個(gè)值,但是insert_id更有效,因?yàn)樗堰@個(gè)值保存在了客戶端,再次需要時(shí)不用重復(fù)執(zhí)行查找。每次有新的插入之后,這個(gè)值都會(huì)改變,所以你必須重新得到這個(gè)AUTO_INCREMENT 值。與此相對(duì),LAST_INSERT_ID() 的結(jié)果保存在服務(wù)器上,所以是持久穩(wěn)固的,它不會(huì)因?yàn)閯e的查詢語(yǔ)句執(zhí)行而改變。

一些有用的DBI模塊和工具


模塊DBI::Utils 包含了其他一些有趣的方法(包括子模塊中的方法):

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

資源


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

   

你會(huì)發(fā)現(xiàn)下面這些額外資源對(duì)你很好的使用Ruby DBI很有幫助:

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Visual Basic數(shù)據(jù)庫(kù)操作方法小結(jié)
[翻譯]
初識(shí)Mybatis--總結(jié)Mybatis的基礎(chǔ)知識(shí)點(diǎn)
ORACLE跨數(shù)據(jù)庫(kù)查詢的方法
項(xiàng)目管理工具 RedMine
SQLite學(xué)習(xí)筆記
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服