Ruby / DBIチュートリアル

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

DBIはRubyのDatabaseIndependent Interfaceの略です。つまり、DBIはRubyコードと基盤となるデータベースの間に抽象化レイヤーを提供し、データベースの実装を非常に簡単に切り替えることができます。これは、使用されている実際のデータベースに関係なく、一貫したデータベースインターフェイスを提供する一連のメソッド、変数、および規則を定義します。

DBIは次のものとインターフェースできます-

  • ADO(ActiveXデータオブジェクト)
  • DB2
  • Frontbase
  • mSQL
  • MySQL
  • ODBC
  • Oracle
  • OCI8(Oracle)
  • PostgreSQL
  • Proxy/Server
  • SQLite
  • SQLRelay

DBIアプリケーションのアーキテクチャ

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

Ruby DBIの一般的なアーキテクチャは、2つのレイヤーを使用します-

  • データベースインターフェイス(DBI)層。このレイヤーはデータベースに依存せず、通信しているデータベースサーバーのタイプに関係なく同じ方法で使用される一連の一般的なアクセス方法を提供します。

  • データベースドライバー(DBD)レイヤー。このレイヤーはデータベースに依存します。さまざまなドライバーがさまざまなデータベースエンジンへのアクセスを提供します。MySQL用、PostgreSQL用、InterBase用、Oracle用などのドライバーがあります。各ドライバーは、DBIレイヤーからの要求を解釈し、それらを特定のタイプのデータベースサーバーに適した要求にマップします。

前提条件

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

このモジュールは、上記で説明したようにDBDとして機能し、からダウンロードできます。 https://www.tmtm.org/en/mysql/ruby/

Ruby / DBIの入手とインストール

次の場所からRubyDBIモジュールをダウンロードしてインストールできます-

https://imgur.com/NFEuWe4/embed

このインストールを開始する前に、root権限を持っていることを確認してください。次に、以下の手順に従います-

ステップ1

$ tar zxf dbi-0.2.0.tar.gz

ステップ2

配布ディレクトリdbi-0.2.0に移動し、そのディレクトリの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
   # connect to the MySQL server
   dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123")
   # 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

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

Server version: 5.0.45

データソースとの接続が確立されると、データベースハンドルが返され、に保存されます。 dbh それ以外の場合はさらに使用する dbhはnil値に設定され、e.erre :: 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
   # connect to the MySQL server
   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
   # disconnect from server
   dbh.disconnect if dbh
end

準備と実行の使用

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

レコードの作成には次の手順があります-

  • INSERTステートメントを使用したSQLステートメントの準備。これは、prepare 方法。

  • SQLクエリを実行して、データベースからすべての結果を選択します。これは、execute 方法。

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

  • すべてがうまくいけば、 commit この操作以外の場合はできます rollback 完全なトランザクション。

以下は、これら2つの方法を使用するための構文です-

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

これらの2つの方法を使用して合格することができます bindSQLステートメントへの値。入力する値が事前に指定されていない場合があります。このような場合、バインディング値が使用されます。疑問符(?)は実際の値の代わりに使用され、実際の値はexecute()APIを介して渡されます。

以下は、EMPLOYEEテーブルに2つのレコードを作成する例です。

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   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
   # disconnect from server
   dbh.disconnect if dbh
end

一度に複数のINSERTがある場合は、最初にステートメントを準備してから、ループ内で複数回実行する方が、ループを介して毎回doを呼び出すよりも効率的です。

READ操作

任意のデータベースでのREAD操作は、データベースからいくつかの有用な情報をフェッチすることを意味します。

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

レコードのフェッチは次の手順で実行されます-

  • 必要な条件に基づいてSQLクエリを準備します。これは、prepare 方法。

  • SQLクエリを実行して、データベースからすべての結果を選択します。これは、execute 方法。

  • すべての結果を1つずつフェッチし、それらの結果を印刷します。これは、を使用して行われますfetch 方法。

  • ステートメントハンドルを解放します。これは、finish 方法。

以下は、給与が1000を超えるEMPLOYEEテーブルからすべてのレコードをクエリする手順です。

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   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
   # disconnect from server
   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

データベースからレコードをフェッチするためのショートカットメソッドは他にもあります。興味がある場合は、結果のフェッチを実行してください。それ以外の場合は、次のセクションに進んでください。

更新操作

UPDATE任意のデータベースでの操作とは、データベースですでに使用可能な1つ以上のレコードを更新することを意味します。以下は、SEXが「M」であるすべてのレコードを更新する手順です。ここでは、すべての男性の年齢を1年増やします。これには3つのステップが必要です-

  • 必要な条件に基づいてSQLクエリを準備します。これは、prepare 方法。

  • SQLクエリを実行して、データベースからすべての結果を選択します。これは、execute 方法。

  • ステートメントハンドルを解放します。これは、finish 方法。

  • すべてがうまくいけば、 commit この操作以外の場合はできます rollback 完全なトランザクション。

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   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
   # disconnect from server
   dbh.disconnect if dbh
end

DELETE操作

データベースから一部のレコードを削除する場合は、DELETE操作が必要です。以下は、AGEが20を超えるEMPLOYEEからすべてのレコードを削除する手順です。この操作は次の手順を実行します。

  • 必要な条件に基づいてSQLクエリを準備します。これは、prepare 方法。

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

  • ステートメントハンドルを解放します。これは、finish 方法。

  • すべてがうまくいけば、 commit この操作以外の場合はできます rollback 完全なトランザクション。

#!/usr/bin/ruby -w

require "dbi"

begin
   # connect to the MySQL server
   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
   # disconnect from server
   dbh.disconnect if dbh
end

トランザクションの実行

トランザクションは、データの整合性を保証するメカニズムです。トランザクションには、次の4つのプロパティが必要です-

  • Atomicity −トランザクションが完了するか、まったく何も起こりません。

  • Consistency −トランザクションは一貫性のある状態で開始し、システムを一貫性のある状態のままにする必要があります。

  • Isolation −トランザクションの中間結果は、現在のトランザクションの外部には表示されません。

  • Durability −トランザクションがコミットされると、システム障害が発生した後でも、影響は持続します。

DBIは、トランザクションをコミットまたはロールバックするための2つの方法を提供します。トランザクションを実装するために使用できるtransactionと呼ばれるもう1つのメソッドがあります。トランザクションを実装するための2つの簡単なアプローチがあります-

アプローチI

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

dbh['AutoCommit'] = false # Set auto commit to 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番目のアプローチは、トランザクション方式を使用します。トランザクションを構成するステートメントを含むコードブロックを使用するため、これはより簡単です。取引方法は、次に呼び出すには、ブロックを実行コミットロールバックブロックが成功したか失敗したかどうかに応じて、自動的に-

dbh['AutoCommit'] = false # Set auto commit to 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 方法。

dbh.commit

ロールバック操作

1つ以上の変更に満足できず、それらの変更を完全に元に戻したい場合は、 rollback 方法。

これは、を呼び出す簡単な例です。 rollback 方法。

dbh.rollback

データベースの切断

データベース接続を切断するには、disconnectAPIを使用します。

dbh.disconnect

ユーザーが切断方式でデータベースへの接続を閉じた場合、未処理のトランザクションはDBIによってロールバックされます。ただし、DBIの実装の詳細に依存する代わりに、アプリケーションはコミットまたはロールバックを明示的に呼び出す方がよいでしょう。

エラーの処理

エラーの原因はたくさんあります。いくつかの例は、実行されたSQLステートメントの構文エラー、接続の失敗、またはすでにキャンセルまたは終了したステートメントハンドルのフェッチメソッドの呼び出しです。

DBIメソッドが失敗すると、DBIは例外を発生させます。DBIメソッドは、いくつかのタイプの例外のいずれかを発生させる可能性がありますが、2つの最も重要な例外クラスはDBI :: InterfaceErrorDBI :: DatabaseErrorです。

これらのクラスの例外オブジェクトには、エラー番号、説明的なエラー文字列、および標準エラーコードを表すerrerrstr、およびstateという名前の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
   # disconnect from server
   dbh.disconnect if dbh
end

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

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

trace(mode, destination)

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

メソッドを使用したコードブロック

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

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

  • dbh.prepare-このメソッドは、ステートメント・ハンドルを生成し、それをすることが推奨され仕上げブロックの最後に。ブロック内で、ステートメントを実行するには、executeメソッドを呼び出す必要があります。

  • dbh.execute−このメソッドは、ブロック内でexecuteを呼び出す必要がないことを除いて同様です。ステートメントハンドルは自動的に実行されます。

例1

DBI.connect 次のように、コードブロックを取得し、データベースハンドルを渡し、ブロックの最後でハンドルを自動的に切断します。

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

例2

dbh.prepare コードブロックを受け取り、ステートメントハンドルをそれに渡し、次のようにブロックの最後で自動的にfinishを呼び出します。

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トランザクションメソッドも、上記で説明したコードブロックを取ります。

ドライバー固有の機能と属性

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

ドライバー固有の属性がサポートされており、を使用して設定または取得できます。 []= または [] メソッド。

シニア番号 機能と説明
1

dbh.func(:createdb, db_name)

新しいデータベースを作成します。

2

dbh.func(:dropdb, db_name)

データベースを削除します。

3

dbh.func(:reload)

リロード操作を実行します。

4

dbh.func(:shutdown)

サーバーをシャットダウンします。

5

dbh.func(:insert_id) => Fixnum

接続の最新のAUTO_INCREMENT値を返します。

6

dbh.func(:client_info) => String

バージョンの観点からMySQLクライアント情報を返します。

7

dbh.func(:client_version) => Fixnum

バージョンの観点からクライアント情報を返します。:client_infoに似ていますが、stingの代わりにfixnumを返します。

8

dbh.func(:host_info) => String

ホスト情報を返します。

9

dbh.func(:proto_info) => Fixnum

通信に使用されているプロトコルを返します。

10

dbh.func(:server_info) => String

バージョンの観点からMySQLサーバー情報を返します。

11

dbh.func(:stat) => String

データベースの現在の状態を返します。

12

dbh.func(:thread_id) => Fixnum

現在のスレッドIDを返します。

#!/usr/bin/ruby

require "dbi"
begin
   # connect to the MySQL server
   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