Ruby DBI モジュールを使う

Paul DuBois
paul@kitebird.com
訳者
久保健洋
kubo@jiubao.org

Original Document revision: 1.02
Original Last update: 2003-05-27
翻訳バージョン: 0.9.5

目次


はじめに


Ruby DBI を使うと、いろんな種類のデータベースを同じAPIでもってrubyから アクセスすることができます。これは、Perl DBI と perl の関係と同じです。 この記事では Ruby DBI を使用したRubyスクリプトの書き方を説明します。こ の文書は DBI 仕様書に説明を追加するものであって、DBI 仕様書そのものを 置き換えるものではありません。したがって、DBI 仕様書は必ず読んでくださ い。本文書で足りない場合は、「参考情報」を参照し てください。

Ruby DBI のアーキテクチャはおおまかに以下の2つの層(レイヤ)から成り立っ ています。

この記事では MySQL データベースドライバを例にとります。しかしあなたの 使用するデータベースが MySQL でなくても、ほとんどのことは同様に使用す ることができます。

前準備

Ruby DBI は汎用的なDBI層のコードと、DBDレベルの様々なドライバから成り 立っています。これらのドライバを使用するときにはほとんどの場合、それ用 のソフトウェアを追加でインストールする必要があります。例えば MySQL の DBDドライバそのものは Ruby で書かれており、DBIから渡されたリクエストを Ruby MySQL モジュールのリクエストへと変換して渡します。そして、Ruby MySQL モジュールそのものは C で書かれており、DBDドライバから渡されたリ クエストを MySQL の C クライアントライブラリへと変換して渡します。 つまり、DBI を使うスクリプトを書いて、MySQL データベースへと接続する場 合には、Ruby MySQL モジュールと C API との両方を追加インストールする必 要があります。Ruby MySQL モジュールについての情報は 「参考情報」に記載されている参考文献を見てください。ここでは MySQL モジュールはすでにインストールされており、使用できる状態にあるとみなし ます。

インストール

MySQL の C クライアントライブラリと Ruby MySQL モジュールの準備が終わっ たら、Ruby DBI モジュールのインストールが可能となります。Ruby DBI モ ジュールは以下のサイトから取得できます。

   http://rubyforge.net/projects/ruby-dbi/
DBIモジュールは圧縮されたtarファイルとして配布されているので、ダウン ロードした後に展開する必要があります。例えば、現在のバージョンが 0.0.19 とすると、配布ファイルは以下のコマンドで展開されます。
   % tar zxf ruby-dbi-all-0.0.19.tar.gz
   (訳者註: GNU tar の場合)
   % gunzip < ruby-dbi-all-0.0.19.tar.gz | tar xf -
   (訳者註: 商用UNIXのOS附属の tar の場合)
配布パッケージを展開したら、展開したファイルのトップディレクトリへ移動し、 そのディレクトリにある setup.rb スクリプトを使ってインストールするパッ ケージの特定を行います。 一般的には、以下のように config 引数の後にはなにも引数をつけません。
   % ruby setup.rb config
このように実行すると、デフォルトですべてのドライバがインストール対象と なります。インストールするドライバを選択したい場合、--with オプションに ドライバの名前を列挙します。例えば、DBI のメイン部分と MySQL の DBD レ ベルのドライバのみをインストールするときは、次のコマンドを発行します。
   % ruby setup.rb config --with=dbi,dbd_mysql
インストールパッケージの設定が終わったら、ビルドしてインストールします。
   % ruby setup.rb setup
   % ruby setup.rb install
このコマンドは root で実行しなければならない場合があります。

この記事では以降、以下の表記を慣習として使用します。

単純なDBIスクリプト

Ruby DBI モジュールがインストールされているなら、Rubyプログラムから MySQL サーバへ接続できるようになっています。 この記事では、サーバはローカルホストで動いており、test という名前のデー タベースへ testuser、testpass というユーザ名、パスワードで接続できると みなします。testuser を作成するには、MySQL の root ユーザでサーバへ接 続して次の文を発行してください。

   mysql> GRANT ALL ON test.* TO 'testuser'@'localhost' IDENTIFIED BY 'testpass';
test データベースがない場合は、次の文を発行してデータベースを作成して ください。
   mysql> CREATE DATABASE test;
別のサーバホスト、ユーザ名、パスワード、データベース名を使用したい場合 は、この記事の以降のスクリプトにでてくる値を適切な値に置き換えてくださ い。

次のスクリプトsimple.rbは、サーバへ接続して、サーバのバージョン を取得して、表示して、接続を切るだけの短いDBIプログラムです。このスク リプトは「参考情報」のリンクからダウンロードでき ます。テキストエディタで直接作成してもかまいません。

   # simple.rb - Ruby DBI を使用した簡単なMySQLスクリプト

   require "dbi"

   begin
       # MySQLサーバへ接続
       dbh = DBI.connect("dbi:Mysql:test:localhost", "testuser", "testpass")
       # サーババージョンの文字列を取得して、表示する。
       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
       # サーバから切断
       dbh.disconnect if dbh
   end

simple.rbスクリプトからはDBIの基本的なコンセプトが読み取れます。 このセクションの残りではDBIがどのように働くかを説明し、次のセクション からDBIプログラミング特有の側面について例を出しつつ詳細に記述していき ます。

simple.rbはDBIモジュール要求するrequireの行から始ま ります。この行がないと、DBI メソッド呼び出しが失敗します。スクリプトの 残り部分はbegin/rescue/ensureの中に置いてあります。

connectメソッドはデータベースサーバへの接続を確立し、サーバと の通信に使用するデータベースハンドルを戻します。第一引数には、ドライバ 名(MySQLの場合はMysql)、デフォルトのデータベース名、サーバの ホスト名を示すデータソース名(DSN, data source name)をわたします。 第二引数と第三引数は MySQL アカウントのユーザ名とパスワードです。DSNの 値を書く方法は他にもあります。他の方法に関しては後のセクションの「サーバ接続の補足」であつかわれます。

simple.rbはデータベースハンドルを使ってselect_oneメソッ ドを呼んでいます。このメソッドは、問い合わせをサーバへ送り、結果列の最 初の行を配列として戻すメソッドです。問い合わせSELECT VERSION()は値をひとつ戻します。したがって、バージョン文字列は row[0]として利用できます。これは配列の最初のそしてただひとつ の項目です。スクリプトを走らせると、結果はこのように表示されます。

   % ruby simple.rb
   Server version: 4.0.13-log
エラーが起こると例外が上ります。様々な種類の例外が起こり得ます。 しかし、データベースの操作に関するエラーのほとんどは DatabaseError例外を引き起こします。この例外のオブジェクトは errerrstrの属性を持っていて、エラー番号とエラーの 内容を記述したメッセージを意味します。 simple.rbはデータベース例外に関連するこれらの値を取得して出力 し、その他の種類の例外は無視します。(本来ならば、rescue ブロック内で 例外を作成し、呼び出し元のコードにわたして処理するべきです。)

simple.rbdisconnectメソッドを呼んでサーバへの接続を 切ります。切断はensureブロックで行い、問い合せを処理している 最中にエラーが起きても接続が確実に切られるようにします。

問合せ処理


RUby DBI を用いてSQL文を実行する方法はたくさんあります。このセクション ででそのうちの何種類かを使用します。ここで記述されなかった方法について はDBI仕様書を参照してください。

本文書で使用するサンプルスクリプトは、大抵の場合、peopleとい う名前のテーブルを使用します。このテーブルは以下の構造をしています。

   CREATE TABLE people
   (
       id INT UNSIGNED NOT NULL AUTO_INCREMENT,    # ID番号
       name CHAR(20) NOT NULL,                     # 名前
       height FLOAT,                               # 身長(インチ単位)
       PRIMARY KEY (id)
   );

結果セットを返さない問合せ処理

行を返さないSQL文は、データベースハンドルのdoメソッドでもって 実行できます。このメソッドは問い合せ文字列1つを引数にとり、問い合わせ の実行で影響の受けた行を戻します。次の例はdoを何回も使用して、 peopleテーブルを作成し小さなテーブルデータを挿入します。

   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文の実行箇所を見てください。スクリプト内でどれだけの数 の行がテーブルに追加されたか取得し、画面に表示しています。

結果セットを返す問合せ処理


SELECTSHOWといったSQL文は行を戻します。このような SQL文を処理するには、SQL文をサーバへ送信して実行し、生成された結果セッ トに含まれる行を取得して、最後に結果セットを破棄する必要があります。

実行方法は何種類もありますが、ここではprepareメソッドを呼んで 文ハンドルを生成し、このハンドルを使用して文を実行し、実行結果を得て、 結果セットを解放する方法を使用します。

   sth = dbh.prepare(SQL文)
   sth.execute
   ... 行を取得 ...
   sth.finish
SQL文を直接executeにわたして、prepareの呼び出しをス キップする方法もあります。
   sth = dbh.execute(SQL文)
   ... 行を取得 ...
   sth.finish
SQL文を実行した後に結果セットから検索結果を得る方法は何種類もあります。 そのうちの一つとして、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はイテレータとして使う方法もあります。これは eachをイテレータとして呼んだときと同じです。fetcheachも等価です。
   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
fetcheachDBI::Rowオブジェクトを生成しま す。行の中身をアクセスするには、DBI::Rowオブジェクトのメソッドを使用し ます。 結果セットより検索結果を取得するメソッドは他に、fetch_arrayfetch_hash があります。このメソッドはDBI::Rowオブジェクトを戻しません。 代りに検索結果を配列やハッシュとして戻し、それ以上行がないときはnilを戻 します。fetch_hashで戻るハッシュはカラム名がキーでカラムの値 が値となっています。どちらのメソッドもブロックなしでも、イテレータとし ても呼ぶことができます。次はfetch_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
データベースハンドルのメソッドを利用すると、execute-fetch-finishの一連の 操作を個々に実行しなくても良くなります。次のメソッドはこれらの仕事を一 度に行い、結果を戻します。
   row = dbh.select_one(statement)
   rows = dbh.select_all(statement)
select_oneは問合せを実行して最初の一行を配列として戻します。 問合せが一行も返さないときはnilを戻します。 select_allDBI::Rowオブジェクトの配列を戻します。 (このオブジェクトの中身は以前説明した方法にアクセスできます。) 問合せが一行も返さないときは空の配列となります。

MySQLドライバは結果セットのメタデータを調べて行の値を対応するRubyのデー タタイプへ変換します。(言い換えると、例えば、people テーブルから取り出されたidnameheightの 値がFixnumStringFloatのオブジェクトとし て戻されるということです。) しかし、カラムの値がNULLの場合は 注意してください。この場合は、NULL値は結果セットではnilとして 表現され、その種類はNilClassとなります。また、どのような型に 変換するかはDBI仕様書では規定されておらず、DBDドライバによって変換先が 異なる場合があります。

クオート、プレースホルダー、パラメータ束縛

Ruby DBI にはプレースホルダー機構があり、問合せ文字列のデータの 値を直接取り込まなくても良いようになっています。代わりにSQL文の中に特 別な印をつけて、データの値が入る場所を示します。SQL文を実行するときに は、プレースホルダーにバインドする値を与えておきます。DBIはプレースホ ルダーの現れる場所のSQL文をバインドした値に置き換えます。このとき文字 列の値はクオートで囲って、必要なら特殊文字をエスケープします。これを使 うと、与えようとする文字に特殊文字が含まれているかどうか気にせずに、ま た、自身でクオートで囲うことなしに簡単にSQL文を組み立てることができま す。プレースホルダー機構はNULL値も適切にあつかいます。 nilをデータとして与えるだけで、クオートされていない NULL値としてSQL文中に置かれます。

次の例はこれがどのように働くかを説明します。例として、クオートを含む Na'ilという名前で身長が76インチの人をpeopleテーブルにに追加す ると想定しましょう。まず、データがINSERT文のどこに入るかを示 すために、プレースホルダーの印'?'をシングルクオートなしで使 い、次いで、doの引数にSQL文につづけて、追加の引数としてデータ を与えます。

   dbh.do("INSERT INTO people (id, name, height) VALUES(?, ?, ?)",
           nil, "Na'il", 76)
doにより生成されてサーバへ送られる最終的なSQL文は次のようにな ります。
   INSERT INTO people (id,name,height) VALUES(NULL,'Na\'il',76)
SQLを何回も実行しようと考えている場合は、文ハンドルを得るために prepareで準備してから、executeでデータを引数として与 えながら実行することができます。 people.txtという名のデータファイルに、peopleテーブルに挿 入する名前/身長のペアがタブ区切りで行毎にはいっていると仮定しましょう。 次の例はファイルを呼んで一行のデータを得て、前もって準備した INSERT文を各行ごとに実行します。
   # 挿入ループで使用する文ハンドルを用意する。
   sth = dbh.prepare("INSERT INTO people (id, name, height) VALUES(?, ?, ?)")

   # ファイルから一行づつ読んで、値に分けて、データベースへ挿入する。
   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
SQL文を prepare した後にループ内で何回も実行したほうが、ループ毎に doを呼び出す(繰り返し毎にprepareexecuteの 両方を呼ぶのと同等)よりも効率的です。問い合わせ実行計画を準備して、 executeの呼び出し毎に実行計画を再利用するデータベースの場合、 これは重大な効率上の差異となります。MySQLは実行計画を再利用はできませ んが、Oracleは再利用します。

SELECT文にプレースホルダーを使う場合、SQL文を最初の準備するか にするかどうかで適切な方法がかわります。

他のドライバは別の形式のプレースホルダーでも受け付けるかもしれません。 また、別の形式でないと受け付けないかもしれません。例えば、プレースホル ダーを :name:n として名前付きや数値付きの形式で 書けるかもしれません。

quoteメソッドはデータ値をクオートで囲い、特殊文字をエスケープ して、結果を戻します。これは他のプログラムで実行するSQL文を組み立てる のに便利です。例えば、データファイルpeople.txtを読んで、 INSERT文のかたまりに変形して、コマンドラインクライアントの mysqlといったプログラムで処理させる場合、次のようにします。

   # ファイルから一行づつ読んで、値に分けて、INSERT文を書き出す。
   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

メタデータの問い合わせ

INSERTDELETEといった結果セットを戻さないSQL文の場 合、doメソッドは処理された行数を戻します。

SELECTといった行を戻すSQL文の場合、executeを呼んだ後 に文ハンドルを使い、結果セットの行数やカラム数、個々のカラムの情報を得 ることができます。

次のスクリプトは問い合わせからメタデータを得る方法を示します。
   sth = dbh.execute(query)

   puts "問い合わせ: " + query
   if sth.column_names.size == 0 then
       puts "問い合わせには結果セットがありません。"
       printf "影響を受けた行の数: %d\n", sth.rows
   else
       puts "問い合わせには結果セットがあります。"
       rows = sth.fetch_all
       printf "行数:     %d\n", rows.size
       printf "カラム数: %d\n", sth.column_names.size
       sth.column_info.each_with_index do |info, i|
           printf "--- カラム %d (%s) ---\n", i, info.name
           printf "精度:     %s\n", info.precision
           printf "スケール: %s\n", info.scale
       end
   end
   sth.finish
注意事項: 古いバージョンのこの文書では、SELECT文の結果の行数 をsth.rowsで得ることができると述べていましたが、これはサポー トされていません。(現在のところ MySQL ドライバではたまたま動きますが、 この挙動は信頼しないでください。)

コードブロックつきのメソッド


ハンドルを生成するメソッドのうちいくつかはコードブロック付きで呼ぶこと ができます。ブロック付きで実行した時、ハンドルはコードブロックのパラメー タとして渡され、ブロックの実行が終了したら自動的にハンドルが解放されま す。

これらのハンドルを生成するメソッドそれぞれに対してコードブロックを使っ た例です。
   # connectはコードブロックをとり、データベースハンドルをブロックに渡します。
   # ブロックの最後では自動的にハンドルを切断します。

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

       # prepareはコードブロックをとり、文ハンドルをブロックに渡します。
       # ブロックの最後では自動的にfinishを呼びます。

       dbh.prepare("SHOW DATABASES") do |sth|
           sth.execute
           puts "Databases: " + sth.fetch_all.join(", ")
       end

       # executeはコードブロックをとり、文ハンドルをブロックに渡します。
       # ブロックの最後では自動的にfinishを呼びます。

       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, data source name)で、 作成しようとする接続の種類を区別します。残りの2つの引数はMySQLアカウ ントのユーザ名とパスワードです。

DSN は以下の書式ならどれでも受け付けます。

   dbi:driver_name
   dbi:driver_name:db_name:host_name
   dbi:driver_name:key=val;key=val...
DSNは常にdbiもしくはDBIで始まります。(すべて大文字か すべて小文字かのどちらかです。両者の混在は受け付けません。) 続けて、ド ライバ名となります。MySQLの場合はドライバ名はMysqlです。正確 に先頭のみを大文字にして用いたほうが良いでしょう。(DBI仕様書にはドライ バ名は大文字小文字どちらでも良いと指示されてますが、最新の 0.0.18 でも それが常に真とはかぎりません。) 他のドライバを使用する場合は、適切なド ライバ名を使う必要があります。

dbi(もしくはDBI)とドライバ名は常にDSNに与える必要が あります。ドライバ名に続けて何も指定されてないときは、ドライバは(おそ らく)デフォルトのデータベースとホスト名を使って接続しようとします。 MySQLドライバの場合はデータベース名を指定する必要があるので、DBIを使っ たMySQLプログラミングでは第一の書式は使えません。他の書式を使ってくだ さい。第二の書式は2つの値を要求します。コロンで区切られたデータベース 名とホスト名です。第三の書式はセミコロンで区切られた param=valueの形式でパラメータの指定を行います。次のDSNはすべ て同じ意味をもちます。

   dbi:Mysql:test:localhost
   dbi:Mysql:host=localhost;database=test
   dbi:Mysql:database=test;host=localhost
param=valueの形式を使ったDSNの構文は最も柔軟です。というのも、 パラメータを任意の順番で指定できるからです。また、ドライバ固有のパラメー タを指定できる可能性もあります。ドライバは受け付けることのできる接続パ ラメータを拡張することができるからです。MySQLの場合は、hostdatabaseの他の追加のパラメータはportsocketflagです。(これらのパラメータは、 DBD::Mysqlの下にある Ruby MySQL モジュールの real_connectメソッドの対応するパラメータに渡されます。)

エラー処理とデバッグ

DBIメソッドが失敗するとDBIは例外を上げます。DBIメソッドはどんな例外で も上げる可能性はありますが、データベースに関する操作に対しては、それに 関係する例外クラス、DatabaseErrorがあります。このクラスの例外 オブジェクトにはerrerrstrstateという3 つの属性があります。DBIドキュメントはこれらの属性の意味を特定してはい ませんが、それぞれエラー番号、説明的なエラー文字列、そしてある種の「標 準」エラーコードをあらわしているように見えます。MySQLドライバは現時点 ではエラー文字列のみを提供しています。しかし、エラー番号を同様に戻すよ うにするドライバへパッチは簡単なことです。両方の値が利用可能と仮定する と、例外が起こったときにこれらの値を得るには次のようにします。

   rescue DBI::DatabaseError => e
       puts "An error occurred"
       puts "Error code: #{e.err}"
       puts "Error message: #{e.errstr}"
実行しようとするスクリプトが何をしているのかデバッグ情報を実行の順序ど おりに得るには、トレース可能な状態にしてください。そうするには、まず最 初にdbi/traceモジュールを読み込みます。
   require "dbi/trace"
dbi/tracedbiモジュールによって自動的には読み込まれ ません。というのも、AspectRモジュールのバージョン0.3.3以降に依存するか らです。AspectRはあなたのマシンに存在しないかもしれません。

dbi/traceモジュールはtraceメソッドを提供します。 traceメソッドでトレースのモードと出力先を設定をします。

   trace(mode, destination)
modeは 0(off)、1、 2、3 の値をとります。 destinationIOオブジェクトでないといけません。 デフォルト値はmodeは2で、destinationSTDERRです。

traceはクラスメソッドとして呼び出されると、続いて作成されるす べてのハンドルに対して影響します。または、ドライバ、データベースハンド ル、文ハンドルに対して個々にインスタンスメソッドとして呼び出すこともで きます。インスタンスメソッドとして呼ばれると、そのオブジェクトに由来す るすべてのオブジェクトに対してもトレースの設定が引き継がれます。例えば、 データベースハンドルに対してトレースを有効にすると、そこから作成された 文ハンドルのトレースの設定は同じになります。

トランザクション・サポート


トランザクションの使用方法はデータベースによって異なりますが、DBIはト ランザクションを抽象化して、同じ手順で使える機能を提供します。しかし、 抽象化が使えるかどうかは使用しているデータベースエンジンがトランザクショ ンをサポートしているかどうか、さらには使用するドライバがDBIレベルの抽 象化を実装しているかどうかに依存します。MySQLドライバの場合は、この抽 象化は DBI 0.0.19 より前では機能していません。したがって、トランザクショ ンを実行するには明示的にSQL文を使って自動コミットレベル、コミット、ロー ルバックを制御しないといけません。例えば以下のようにです。

   dbh.do("SET AUTOCOMMIT=0")
   dbh.do("BEGIN")
   ... statements that make up the transaction ...
   dbh.do("COMMIT")
DBI 0.0.19 以降では、MySQL でトランザクションの抽象化を利用できます。 抽象化の側面のひとつに、自動コミットのレベルをデータベースハンドルの AutoCommit属性の指定で設定できることにあります。
   dbh['AutoCommit'] = true
   dbh['AutoCommit'] = false
自動コミットが無効な間は(falseを設定)、トランザクションは2つ の方法で制御できます。次の例でその2つのアプローチを説明します。例とし てaccountテーブルを用い、資金をひとりの人から別の人にわたしま す。

ドライバ固有の機能を呼び出す。

DBIはデータベースに依存する特別な機能を利用するためのfunc メソッドを提供してます。例えば MySQL の C API には、使用中のコネクショ ンでの最新のAUTO_INCREMENTの値を戻すmysql_insert_id()関数があ ります。Ruby MySQL モジュールはデータベースハンドルのメソッドinsert_id を経由してこの関数を呼び出します。また、DBD::Mysql は DBI の funcメカニズムを経由してinsert_idにアクセスします。

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)            リロード操作を実行する。
   dbh.func(:shutdown)          サーバをシャットダウンする。
あなたの使用しているMySQLクライアントライブラリのバージョンが MySQL 4 以上の場合、createdbdropdbが使用できないことに注意 してください。これらのメソッドは MySQL 4 より Ruby MySQL モジュールで 使用してはいけない関数(deprecated functions)となっています。

同じことを実現するのにドライバ固有の機能を使用した場合と通常のSQLを発 行して実現する方法の2つがある場合、ドライバ固有の機能を使用したほうが 効率的である場合があります。例えば、 SELECT LAST_INSERT_ID() を発行した結果は DBD::Mysqlinsert_id関数の戻り値でも得ることができ ます。両者ほほとんどの場合同じ結果を戻します。しかしinsert_id 関数のほうがより効率的です。というのもinsert_idは、問い合わせ を発行することなしにクライアント側に保持された値を戻すからです。 効率上の利点を追及するには、注意深く関数呼び出しを行う必要があります。 insert_idの値はそれぞれの問い合せの実行毎にリセット されます。そのため、AUTO_INCREMENT値を生成する問い合わせを発 行した後、他の問い合わせを発行する前にアクセスしないといけません。対照 的にLAST_INSERT_ID()の値はサーバ側にもっと長い時間保持されま す。AUTO_INCREMENT値を生成する問い合わせが発行されない限りリ セットされることはありません。

その他の便利な機能

DBI::Utilsモジュールには興味深いメソッドがいくつかあります。

asciiメソッドとtableメソッドにはオプションの引数がい ろいろあります。オプションによって出力フォーマットや出力先を細かく制御 できます。オプションの情報を得るには、モジュールのソースコードを見てく ださい。

参考情報


この記事の例で使用したスクリプトは以下の場所よりダウンロードできます。

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

ここには "Using the Ruby MySQL Module(英語)" という記事があり、 DBD::Mysql(DBD層のMySQLドライバ)の土台となっているRuby MySQLモジュール の説明をしてます。

Ruby DBI を使用するのに役立つ情報は以下の場所より見付けられます。