<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
簡介
想想php當時爲什麼這麼流行,一點原因就是因爲有了Mysql這個天生的搭檔。現在,mysql幾乎是opensource裏用的最多的數據庫了。在Ruby裏,可以通過Tomita Masahiro 的MySQL模塊,它提供了一個供Ruby使用的客戶端api,其實就是對mysql c API的包裝。
本文主要要講mysql模塊的安裝,編寫基於Ruby+mysql的腳本程序。
安裝MySQL模塊
要想用Ruby的MySQL模塊,你要先確保你的MySQL C客戶端API頭文件和庫文件已經成功安裝,這是必須的,因爲mysql 模塊是基於這個寫的。
首先從http://www.tmtm.org/en/mysql/ruby/ 下載軟件包,然後解壓縮,比如:
% tar zxvf mysql-ruby-2.4.4a.tar.gz
然後進入到解壓縮之後的頂層目錄,開始configure(ruby特有的方式)。
% ruby extconf.rb
extconf.rb會自動檢查mysql頭和庫文件,如果找到了,你可以直接進行下一步,如果沒找到,需要手動填寫參數,比如:
% ruby extconf.rb /
--with-mysql-include=/usr/local/mysql/include/mysql /
--with-mysql-lib=/usr/local/mysql/lib/mysql
假設mysql的頭和庫文件分別如上面所示的那樣。
上述操作成功之後,就可以運行make了
% make
% make install(用root運行)
MySQL模塊概覽
MySQL模塊包括4個類:
• Mysql
主類,提供了諸如連接數據庫,發送查詢語句,管理操作等功能。
• MysqlRes
結果集類,用來產生查詢得到的結果。
• MysqlField
Metadata類,它包含結果集中字段的信息,比如字段名,類型,大小等。
• MysqlError
異常類,當其他三個類出現錯誤時,要用的到。
因爲大體上來說mysql模塊是對mysql c API的包裝,所以它的函數名字也是有規律的,比如c api的函數名是mysql_real_connect(),在Ruby裏,就是real_connect(),可以看出,就是去掉了前面的mysql_前綴。
第一個簡單例子
首先確保我們在本地數據庫有一個數據庫叫rubydb,一個用戶test,密碼也是test。
例子如下:
# file name : example1.rb
require "mysql"
begin
# connect to the server
dbh = Mysql.real_connect("localhost", "test", "test", "rubydb")
# get server version string and display it
puts "Server version: " + dbh.get_server_info
rescue MysqlError => e
print "Error code: ", e.errno, "/n"
print "Error message: ", e.error, "/n"
ensure
# disconnect from server
dbh.close
end
現在來看一下這個程序:
第一行,包含了mysql模塊,告訴ruby把mysql模塊引入。
Real_connect函數鏈接數據庫,四個參數都很容易理解。其實,mysql模塊還提供了一些別名,比如new,connect和real_connect是等同的。
Dbh(database handle)用來和mysql交互,比如例子中調用get_server_info函數取得服務器相關信息,比如版本。
Begin . . . rescue . . . ensure . . . 是異常處理中講過的東西,類似java的try catch finally機制。如果dbh在與數據庫交互工程中出錯,則被rescue捕獲,並賦給e指向一個MysqlError的異常,這個異常包括兩個只讀屬性:errno,錯誤編號,整數,error,錯誤消息,字符串型。
如果這個程序執行正確,不出錯誤,結果如下:
% ruby example1.rb
Server version: 4.0.12-log
如果執行出錯,比如我們寫了一個錯誤的主機名,把localhost寫成loclahost,則會出錯:
% ruby example1.rb
An error occurred
Error code: 2005
Error message: Unknown MySQL Server Host ’ loclahost’ (1)
處理查詢
我們暫且把sql分爲兩類:dml,ddl(這個不要深究)。Ddl包括create,insert,update,delete;dml包括select,show等。Ddl不需要返回結果集,所以很容易處理;dml需要返回結果集,需要多一些處理過程。
1.對於不需要返回結果集的語句調用query方法就行,如果想知道受影響的行數,可以用affected_rows得到。綜合例子如下:
dbh.query(“drop table test”)
dbh.query(“create table test
id int,
name char(20)
”)
dbh.query(“insert into test valuse(1,’name1’)”)
printf "%d rows were inserted/n", dbh.affected_rows
2.對於需要返回結果的查詢,比如select,需要遵循如下過程:
a. 調用query方法向數據庫發送查詢請求,並得到一個結果集(MysqlRes的一個實例),這個結果集提供了取一行,移動,取得列的元數據(metadata)等方法。
b. 用fetch_row等函數或者迭代等處理每一行數據。
c. 如果你想知道總共返回多少行,可以用num_rows方法。
d. 別忘了最後用free釋放結果集對象。
res = dbh.query("SELECT id,name FROM test1")
while row = res.fetch_row do
printf "%s, %s/n", row[0], row[1]
end
printf "%d rows were returned/n", res.num_rows
res.free
或者用迭代:
res = dbh.query("SELECT id,name FROM test1")
res.each do |row|
printf "%s, %s/n", row[0], row[1]
end
printf "%d rows were returned/n", res.num_rows
res.free
fetch_row 和each 每次都返回一個數組,下標爲0的元素表示第一個列的數據等。此外,還可以用fetch_hash方法,返回一個hash結構,即類似java裏Map的key-value結構:
res = dbh.query("SELECT id,name FROM test1")
while row = res.fetch_hash do
printf "%s, %s/n", row["id"], row["name"]
end
printf "%d rows were returned/n", res.num_rows
res.free
each_hash是each的哈希版本:
res = dbh.query("SELECT id,name FROM test1")
res.each_hash do |row|
printf "%s, %s/n", row["id"], row["name"]
end
printf "%d rows were returned/n", res.num_rows
res.free
默認的時候,哈希中key的值就是列名,但是如果選擇的列有重名的時候,這可能會帶來很多問題,比如下面的語句中的兩個字段都叫做i:
SELECT t1.i, t2.i FROM t1, t2;
如果你用哈希結構來取,只能取得一列的值。爲了解決這種列名衝突問題,你可以在fetch_hash或者each_hase的時候指定with_table=true,這樣,哈希德key就是表明和類名連在一塊的值了,格式就是tbl_name.col_name。
res = dbh.query("SELECT id, name FROM animal")
res.each_hash(with_table = true) do |row|
printf "%s, %s/n", row["test.id"], row["test. name"]
end
printf "%d rows were returned/n", res.num_rows
res.free
如果在查詢語句裏對錶或者列名用了別名,那麼這些別名將作爲哈希裏的key值,而不是原來的表名和列名。
用fetch_row,each,我們必須記住每個字段的位置,才能準確的找到他,這對select * 查詢來說比較困難。而用fetch_hash 和 each_hash責可以避免這種情況,可以根據列名來取列值,而不必去管列的位置如何。
如果指定了參數with_table=true,而查詢的字段中還有表達式,那麼,對應這些表達式的key值中前面的tbl_name部分將是空的(但是”.”還在),比如你有如下查詢:
SELECT i, i+0, VERSION(), 4+2 FROM t;
只有I是表的列名,其他都是表達式,那麼這些列對應於哈希表中的key值分別是: "t.i", ".i+0", ".VERSION()",和 ".4+2".