Ruby データベース アクセス - DBI チュートリアル


この章では、Ruby を使用してデータベースにアクセスする方法を説明します。 Ruby DBI モジュールは、Perl DBI モジュールと同様に、データベースに依存しない Ruby スクリプトへのインターフェイスを提供します。

DBIはDatabase Independent Interfaceの略で、Rubyのデータベース非依存インターフェースを表します。 DBI は、Ruby コードと基礎となるデータベースの間に抽象化レイヤーを提供し、データベース切り替えを簡単に実装できるようにします。一連のメソッド、変数、仕様を定義し、データベースに依存しない一貫したデータベース インターフェイスを提供します。

DBI は以下と対話します:

  • ADO (ActiveX Data Objects)

  • DB2

  • Frontbase

  • mSQL

  • MySQL

  • ODBC

  • オラクル

  • OCI8 (Oracle)

  • PostgreSQL

  • プロキシ/サーバー

  • SQLite

  • SQLRelay

DBIはどのデータベースからも独立していますバックエンドで利用可能です。 Oracle、MySQL、Informix のいずれを使用している場合でも、DBI を使用できます。以下のアーキテクチャ図はこれを明確に示しています。

Ruby DBI の一般的なアーキテクチャは、ruby_dbi.jpg

    データベース インターフェイス (DBI) 層の 2 つの層を使用します。この層はデータベースから独立しており、データベース サーバーの種類に関係なく使用できる一連のパブリック アクセス方法を提供します。
  • データベース ドライバー (DBD) 層。この層はデータベースに依存しており、異なるドライバーが異なるデータベース エンジンへのアクセスを提供します。 MySQL、PostgreSQL、InterBase、Oracle などはそれぞれ異なるドライバーを使用します。各ドライバーは、DBI 層からのリクエストを解釈し、これらのリクエストを特定のタイプのデータベース サーバーに適切なリクエストにマッピングする責任を負います。
  • インストール

MySQL データベースにアクセスするための Ruby スクリプトを作成する場合は、最初に Ruby MySQL モジュールをインストールする必要があります。

Mysql 開発パッケージをインストールします

# Ubuntu
sudo apt-get install mysql-client
sudo apt-get install libmysqlclient15-dev

# Centos
yum install mysql-devel

Mac OS システムは ~/.bash_profile または ~/.profile ファイルを変更し、次のコードを追加する必要があります:

MYSQL=/usr/local/mysql/bin
export PATH=$PATH:$MYSQL
export DYLD_LIBRARY_PATH=/usr/local/mysql/lib:$DYLD_LIBRARY_PATH

またはソフト接続を使用します:

sudo ln -s /usr/local/mysql/lib/libmysqlclient.18.dylib /usr/lib/libmysqlclient.18.dylib

RubyGems を使用して DBI をインストールする(推奨)

RubyGems 2003 年 11 月頃に作成され、Ruby バージョン 1.9 から Ruby 標準ライブラリの一部となっています。詳細については、以下を確認してください: Ruby RubyGems

gem を使用して dbi と dbd-mysql をインストールします:

sudo gem install dbi
sudo gem install mysql
sudo gem install dbd-mysql

ソース コードを使用してインストールします (Ruby バージョン 1.9 未満ではこの方法を使用します)

このモジュールは DBD であり、http から入手できます。 ://tmtm .org/downloads/mysql/ruby/ からダウンロードします。

最新のパッケージをダウンロードした後、解凍してディレクトリに入り、次のコマンドを実行してインストールします:

% ruby extconf.rb

或者

% ruby extconf.rb --with-mysql-dir=/usr/local/mysql

或者

% ruby extconf.rb --with-mysql-config

次にコンパイルします:

% make

Ruby/DBIを入手してインストールします

Ruby DBIモジュールは以下からダウンロードしてインストールできます。以下のリンク:

https://github.com/erikh/ruby-dbi

インストールを開始する前に、root アクセス権があることを確認してください。次に、以下の手順に従ってインストールしてください:

ステップ 1

git clone https://github.com/erikh/ruby-dbi.git

または、zip パッケージを直接ダウンロードして解凍します。

ステップ 2

ディレクトリ ruby-dbi-master に移動し、ディレクトリ内の setup.rb スクリプトを使用して設定します。最も一般的に使用される設定コマンドは、config パラメータの後にパラメータを指定しないものです。このコマンドは、デフォルトですべてのドライバーをインストールするように構成されています。

$ ruby setup.rb config

より具体的には、 --with オプションを使用して、使用する特定の部分をリストできます。たとえば、メイン DBI モジュールと MySQL DBD レイヤー ドライバーのみを構成する場合は、次のコマンドを入力します:

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

ステップ 3

最後のステップはドライバーを作成することです。次のコマンドを使用してインストールします:

$ ruby setup.rb setup
$ ruby setup.rb install

データベース接続

MySQL データベースが使用されているとします。データベースに接続する前に、次のことを確認してください。

  • データベース TESTDB が作成されていること。

  • TESTDB にテーブル EMPLOYEE を作成しました。

  • このテーブルには、FIRST_NAME、LAST_NAME、AGE、SEX、INCOME のフィールドがあります。

  • TESTDB にアクセスするには、ユーザー ID「testuser」とパスワード「test123」を設定します

  • Ruby モジュール DBI がマシンに正しくインストールされました。

  • あなたは MySQL チュートリアルを視聴し、MySQL の基本操作を理解しました。


以下は、MySQL データベース「TESTDB」への接続の例です:

#!/usr/bin/ruby -w

require "dbi"

begin
     # 连接到 MySQL 服务器
     dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", 
                       "testuser", "test123")
     # 获取服务器版本字符串,并显示
     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

このスクリプトを実行すると、Linux マシン上で次の結果が生成されます。

Server version: 5.0.45

データソースとの接続が確立されている場合、データベースハンドル (データベースハンドル) が返され、その後の使用のために dbh に保存されます。それ以外の場合、dbh は nil 値、e.err および に設定されます。 e::errstr は、それぞれエラー コードとエラー文字列を返します。

最後に、このプログラムを終了する前に、必ずデータベース接続を閉じてリソースを解放してください。

INSERT操作

データベーステーブルにレコードを作成したい場合は、INSERT操作を使用する必要があります。

データベース接続が確立されたら、doメソッドまたはprepareメソッドとexecuteメソッドを使用して、テーブルを作成したり、データテーブルに挿入されるレコードを作成したりする準備が整います。

do ステートメントを使用する

行を返さないステートメントは、do データベース処理メソッドを呼び出すことで実行できます。このメソッドはステートメント文字列パラメータを受け取り、ステートメントの影響を受ける行数を返します。

dbh.do("DROP TABLE IF EXISTS EMPLOYEE")
dbh.do("CREATE TABLE EMPLOYEE (
     FIRST_NAME  CHAR(20) NOT NULL,
     LAST_NAME  CHAR(20),
     AGE INT,  
     SEX CHAR(1),
     INCOME FLOAT )" );

同様に、SQL INSERT ステートメントを実行して、EMPLOYEE テーブルに挿入するレコードを作成できます。

#!/usr/bin/ruby -w

require "dbi"

begin
     # 连接到 MySQL 服务器
     dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", 
                       "testuser", "test123")
     dbh.do( "INSERT INTO EMPLOYEE(FIRST_NAME,
                   LAST_NAME, 
                   AGE, 
         SEX, 
         INCOME)
          VALUES ('Mac', 'Mohan', 20, 'M', 2000)" )
     puts "Record has been created"
     dbh.commit
rescue DBI::DatabaseError => e
     puts "An error occurred"
     puts "Error code:    #{e.err}"
     puts "Error message: #{e.errstr}"
     dbh.rollback
ensure
     # 断开与服务器的连接
     dbh.disconnect if dbh
end

prepareexecute

の使用 DBI の prepare メソッドと execute メソッドを使用して、Ruby コードで SQL ステートメントを実行できます。

レコードを作成する手順は次のとおりです:

  • INSERT ステートメントを含む SQL ステートメントを準備します。これは prepare メソッドを使用して行われます。

  • SQL クエリを実行し、データベースからすべての結果を選択します。これは、executeメソッドを使用して行われます。

  • ステートメントハンドルを解放します。これは finish API を使用して行われます。

  • すべてがうまくいった場合は、そのアクションをコミットします。そうでない場合は、ロールバックしてトランザクションを完了できます。

これら 2 つのメソッドを使用するための構文は次のとおりです:

sth = dbh.prepare(statement)
sth.execute
   ... zero or more SQL operations ...
sth.finish

これら 2 つのメソッドは、bind 値を SQL ステートメントに渡すために使用できます。場合によっては、入力される値が事前に指定されていない場合があり、その場合は限界値が使用されます。実際の値の代わりに疑問符 (?) を使用します。これは、execute() API 経由で渡されます。

次の例では、EMPLOYEE テーブルに 2 つのレコードを作成します:

#!/usr/bin/ruby -w

require "dbi"

begin
     # 连接到 MySQL 服务器
     dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", 
                       "testuser", "test123")
     sth = dbh.prepare( "INSERT INTO EMPLOYEE(FIRST_NAME,
                   LAST_NAME, 
                   AGE, 
         SEX, 
         INCOME)
                   VALUES (?, ?, ?, ?, ?)" )
     sth.execute('John', 'Poul', 25, 'M', 2300)
     sth.execute('Zara', 'Ali', 17, 'F', 1000)
     sth.finish
     dbh.commit
     puts "Record has been created"
rescue DBI::DatabaseError => e
     puts "An error occurred"
     puts "Error code:    #{e.err}"
     puts "Error message: #{e.errstr}"
     dbh.rollback
ensure
     # 断开与服务器的连接
     dbh.disconnect if dbh
end

複数の INSERT を同時に使用する場合は、毎回 do を呼び出すよりも、最初にステートメントを準備してからループ内で複数回実行する方が効率的です。ループを介してさらに多くのことを行います。

READ 操作

データベースに対する READ 操作とは、データベースから有用な情報を取得することを指します。

データベース接続が確立されたら、データベースにクエリを実行する準備が整います。 do メソッド、または prepare メソッドと execute メソッドを使用して、データベース テーブルから値を取得できます。

レコードを取得する手順は次のとおりです:

  • 必要な条件に基づいてSQLクエリを準備します。これは prepare メソッドを使用して行われます。

  • SQL クエリを実行し、データベースからすべての結果を選択します。これは、executeメソッドを使用して行われます。

  • 結果を 1 つずつ取得し、その結果を出力します。これは fetch メソッドを使用して行われます。

  • ステートメントハンドルを解放します。これは finish メソッドを使用して行われます。

次の例では、EMPLOYEE テーブルから給与 (salary) が 1000 を超えるすべてのレコードをクエリします。

#!/usr/bin/ruby -w

require "dbi"

begin
     # 连接到 MySQL 服务器
     dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", 
                       "testuser", "test123")
     sth = dbh.prepare("SELECT * FROM EMPLOYEE 
                        WHERE INCOME > ?")
     sth.execute(1000)

     sth.fetch do |row|
        printf "First Name: %s, Last Name : %s\n", row[0], row[1]
        printf "Age: %d, Sex : %s\n", row[2], row[3]
        printf "Salary :%d \n\n", row[4]
     end
     sth.finish
rescue DBI::DatabaseError => e
     puts "An error occurred"
     puts "Error code:    #{e.err}"
     puts "Error message: #{e.errstr}"
ensure
     # 断开与服务器的连接
     dbh.disconnect if dbh
end

これにより、次の結果が生成されます:

First Name: Mac, Last Name : Mohan
Age: 20, Sex : M
Salary :2000

First Name: John, Last Name : Poul
Age: 25, Sex : M
Salary :2300

データベースからレコードを取得する方法も多数あります。興味がある場合は、Ruby DBI 読み取り操作を確認してください。

更新操作

データベースに対する UPDATE 操作は、データベース内の 1 つ以上の既存のレコードを更新することを指します。次の例では、SEX が「M」であるすべてのレコードを更新します。ここでは、すべての男性の AGE に 1 年を加算します。これは 3 つのステップで行われます:

  • 必要な条件に基づいて SQL クエリを準備します。これは prepare メソッドを使用して行われます。

  • SQL クエリを実行し、データベースからすべての結果を選択します。これは、executeメソッドを使用して行われます。

  • ステートメントハンドルを解放します。これは finish メソッドを使用して行われます。

  • すべてがうまくいった場合は、そのアクションをコミットします。そうでない場合は、ロールバックしてトランザクションを完了できます。

#!/usr/bin/ruby -w

require "dbi"

begin
     # 连接到 MySQL 服务器
     dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", 
                       "testuser", "test123")
     sth = dbh.prepare("UPDATE EMPLOYEE SET AGE = AGE + 1
                        WHERE SEX = ?")
     sth.execute('M')
     sth.finish
     dbh.commit
rescue DBI::DatabaseError => e
     puts "An error occurred"
     puts "Error code:    #{e.err}"
     puts "Error message: #{e.errstr}"
     dbh.rollback
ensure
     # 断开与服务器的连接
     dbh.disconnect if dbh
end

DELETE操作

データベースからレコードを削除したい場合は、DELETE操作を使用する必要があります。次の例では、AGE が 20 を超えるすべてのレコードを EMPLOYEE から削除します。この操作の手順は次のとおりです:

  • 必要な条件に基づいて SQL クエリを準備します。これは prepare メソッドを使用して行われます。

  • SQL クエリを実行して、データベースから必要なレコードを削除します。これは、executeメソッドを使用して行われます。

  • ステートメントハンドルを解放します。これは finish メソッドを使用して行われます。

  • すべてがうまくいった場合は、そのアクションをコミットします。そうでない場合は、ロールバックしてトランザクションを完了できます。

#!/usr/bin/ruby -w

require "dbi"

begin
     # 连接到 MySQL 服务器
     dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", 
                       "testuser", "test123")
     sth = dbh.prepare("DELETE FROM EMPLOYEE 
                        WHERE AGE > ?")
     sth.execute(20)
     sth.finish
     dbh.commit
rescue DBI::DatabaseError => e
     puts "An error occurred"
     puts "Error code:    #{e.err}"
     puts "Error message: #{e.errstr}"
     dbh.rollback
ensure
     # 断开与服务器的连接
     dbh.disconnect if dbh
end

トランザクションを実行する

トランザクションは、トランザクションの一貫性を確保するためのメカニズムです。トランザクションには次の 4 つの属性が必要です:

  • 原子性: トランザクションの原子性とは、トランザクションに含まれるプログラムがデータベースの論理的な作業単位として機能し、それが行うすべてのデータ変更操作が次のいずれかであることを意味します。やるか、まったくやらないか。

  • 一貫性: トランザクションの一貫性とは、トランザクションの実行前後でデータベースが一貫した状態にある必要があることを意味します。データベースの状態がすべての整合性制約を満たしている場合、データベースは一貫性があると言われます。

  • 分離: トランザクションの分離とは、同時トランザクションが互いに分離されていることを意味します。つまり、トランザクション内の操作と操作中のデータはブロックされ、それを変更しようとする他のトランザクションからは見えないようにする必要があります。

  • 耐久性 (耐久性): トランザクションの耐久性とは、システムまたはメディアの障害が発生したときに、コミットされたトランザクションの更新が失われないことを保証することを意味します。つまり、トランザクションがコミットされると、データベース内のデータに対する変更は永続的になり、データベース システムの障害に耐えられる必要があります。データベースのバックアップとリカバリにより耐久性が保証されます。

DBI はトランザクションを実行する 2 つの方法を提供します。 1 つは、トランザクションをコミットまたはロールバックするために使用される commit または rollback メソッドです。トランザクションの実装に使用できる transaction メソッドもあります。次に、トランザクションを実装するための 2 つの簡単なメソッドを紹介します:

メソッド I

最初のメソッドは、DBI の commit メソッドと rollback メソッドを使用して、トランザクションを明示的にコミットまたはキャンセルします:

   dbh['AutoCommit'] = false # 设置自动提交为 false.
   begin
     dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 
             WHERE FIRST_NAME = 'John'")
     dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 
             WHERE FIRST_NAME = 'Zara'")
     dbh.commit
   rescue
     puts "transaction failed"
     dbh.rollback
   end
   dbh['AutoCommit'] = true

メソッド II

2 番目のメソッドは、 トランザクションメソッド。この方法は、トランザクションを構成するステートメントを含むコード ブロックが必要なため、比較的単純です。 transaction メソッドはブロックを実行し、ブロックが正常に実行されたかどうかに応じて commit または rollback を自動的に呼び出します。

   dbh['AutoCommit'] = false # 设置自动提交为 false
   dbh.transaction do |dbh|
     dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 
             WHERE FIRST_NAME = 'John'")
     dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 
             WHERE FIRST_NAME = 'Zara'")
   end
   dbh['AutoCommit'] = true

COMMIT 操作

Commit は、データベースの変更が完了したことを識別する操作です。この操作では、すべての変更は元に戻せません。

以下は、commitメソッドを呼び出す簡単な例です。

     dbh.commit

ROLLBACK 操作

1 つまたは複数の変更に満足できず、これらの変更を完全に元に戻したい場合は、rollback メソッドを使用します。

以下は、rollbackメソッドを呼び出す簡単な例です。

     dbh.rollback

データベースを切断します

データベースから切断する必要がある場合は、切断 API を使用してください。

    dbh.disconnect

ユーザーが切断メソッドを通じてデータベース接続を閉じると、DBI はすべての未処理のトランザクションをロールバックします。ただし、DBI 実装の詳細に依存しなくても、アプリケーションは明示的に commit または rollback を呼び出しても問題ありません。

エラーの処理

エラーの原因はさまざまです。たとえば、SQL ステートメントの実行時に構文エラーが発生したり、接続が失敗したり、取り消されたステートメント ハンドルまたは完了したステートメント ハンドルでフェッチ メソッドが呼び出された場合などです。

DBI メソッドが失敗した場合、DBI は例外をスローします。 DBI メソッドはあらゆる種類の例外をスローできますが、最も重要な 2 つの例外クラスは DBI::InterfaceErrorDBI::DatabaseError です。これらのクラスの

Exception オブジェクトには、errerrstrstate の 3 つの属性があります。サブテーブルは、エラー番号、説明的なエラー文字列、および標準エラー コードを表します。属性の詳細は次のとおりです:

  • err: 発生したエラーの整数表現を返します。DBD がサポートしていない場合は nil を返します。たとえば、Oracle DBD はエラー メッセージの数値部分として ORA-XXXX を返します。

  • errstr: 発生したエラーの文字列表現を返します。

  • state: 発生したエラーの SQLSTATE コードを返します。 SQLSTATE は 5 文字の文字列です。ほとんどの DBD はこれをサポートしていないため、nil が返されます。

上記の例では、次のコードが表示されています:

rescue DBI::DatabaseError => e
     puts "An error occurred"
     puts "Error code:    #{e.err}"
     puts "Error message: #{e.errstr}"
     dbh.rollback
ensure
     # 断开与服务器的连接
     dbh.disconnect if dbh
end

スクリプトの実行時に実行内容に関するデバッグ情報を取得するには、トレースを有効にします。これを行うには、まず dbi/trace モジュールをダウンロードしてから、トレース モードと出力先を制御する trace メソッドを呼び出す必要があります。

require "dbi/trace"
..............

trace(mode, destination)

mode の値は 0 (オフ)、1、2、または 3 です。宛先の値は IO オブジェクトである必要があります。デフォルト値はそれぞれ 2 と STDERR です。

メソッド コード ブロック

には、ハンドルを作成するためのメソッドがいくつかあります。これらのメソッドはコード ブロックを通じて呼び出されます。メソッドでコード ブロックを使用する利点は、コード ブロックへのハンドルがパラメーターとして提供され、ブロックが終了すると自動的にクリアされることです。以下に、この概念を理解するのに役立ついくつかの例を示します。

  • DBI.connect: このメソッドはデータベースハンドルを生成します。データベースを切断するには、ブロックの最後でdisconnectを呼び出すことをお勧めします。

  • dbh.prepare: このメソッドはステートメントハンドルを生成し、ブロックの最後で finish を呼び出すことをお勧めします。ブロック内で、execute メソッドを呼び出してステートメントを実行する必要があります。

  • dbh.execute: このメソッドは dbh.prepare に似ていますが、dbh.execute はブロック内でexecuteメソッドを呼び出す必要がありません。ステートメント ハンドルは自動的に実行されます。

インスタンス 1

DBI.connect はコード ブロックを持つことができ、それにデータベース ハンドルを渡すと、ハンドルはブロックの終わりで自動的に切断されます。

dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", 
                  "testuser", "test123") do |dbh|

インスタンス 2

dbh.prepare にはコード ブロックを含めることができ、それにステートメント ハンドルを渡すと、ブロックの最後で fix が自動的に呼び出されます。

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

インスタンス 3

dbh.execute にはコード ブロックを含めることができ、それにステートメント ハンドルを渡すと、ブロックの最後でfinishが自動的に呼び出されます。

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

DBI transaction メソッドには、上の章で説明したコード ブロックを含めることもできます。

ドライバー固有の関数とプロパティ

DBI を使用すると、データベース ドライバーは追加のデータベース固有の関数を提供でき、ユーザーはこの関数を任意の Handle オブジェクトの func メソッドを通じて呼び出すことができます。

ドライバー固有のプロパティを設定または取得するには、[]= または [] メソッドを使用します。 dbd :: mysqlは、次のドライバー固有の機能を実装します。

2インスタンス
dbh.func(:dropdb, db_name)データベースを削除します。
3dbh.func(:reload)
リロード操作を実行します。
4dbh.func(:shutdown)
サーバーをシャットダウンします。
5dbh.func(:insert_id) => Fixnum
この接続の最新の AUTO_INCREMENT 値を返します。
6dbh.func(:client_info) => String
バージョンに応じて MySQL クライアント情報を返します。
7dbh.func(:client_version) => Fixnum
バージョンに応じてクライアント情報を返します。これは :client_info に似ていますが、文字列の代わりに fixnum を返します。
8dbh.func(:host_info) => String
ホスト情報を返します。
9dbh.func(:proto_info) => Fixnum
通信に使用されるプロトコルを返します。
10dbh.func(:server_info) => String
バージョンに応じて MySQL サーバー側の情報を返します。
11dbh.func(:stat) => Stringb> データベースの現在のステータスを返します。
12dbh.func(:thread_id) => Fixnum
現在のスレッドの ID を返します。
#!/usr/bin/ruby

require "dbi"
begin
   # 连接到 MySQL 服务器
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", 
                       "testuser", "test123") 
   puts dbh.func(:client_info)
   puts dbh.func(:client_version)
   puts dbh.func(:host_info)
   puts dbh.func(:proto_info)
   puts dbh.func(:server_info)
   puts dbh.func(:thread_id)
   puts dbh.func(:stat)
rescue DBI::DatabaseError => e
   puts "An error occurred"
   puts "Error code:    #{e.err}"
   puts "Error message: #{e.errstr}"
ensure
   dbh.disconnect if dbh
end
これにより、次の結果が生成されます:
5.0.45
50045
Localhost via UNIX socket
10
5.0.45
150621
Uptime: 384981  Threads: 1  Questions: 1101078  Slow queries: 4 \
Opens: 324  Flush tables: 1  Open tables: 64  \
Queries per second avg: 2.860