Ruby-database-access
Ruby/DBIチュートリアル
この章では、Rubyを使用してデータベースにアクセスする方法を説明します。 _Ruby DBI_モジュールは、Perl DBIモジュールと同様のRubyスクリプト用のデータベースに依存しないインターフェースを提供します。
DBIはRubyのDatabase Independent Interfaceの略です。つまり、DBIはRubyコードと基になるデータベースとの間に抽象化レイヤーを提供し、データベース実装を非常に簡単に切り替えることができることを意味します。 使用されている実際のデータベースに関係なく、一貫したデータベースインターフェイスを提供する一連のメソッド、変数、および規則を定義します。
DBIは、次とインターフェースすることができます-
- ADO(ActiveXデータオブジェクト)
- DB2
- フロントベース
- mSQL
- MySQL
- ODBC
- オラクル
- OCI8(Oracle)
- PostgreSQL
- プロキシ/サーバー
- SQLite
- SQLRelay
DBIアプリケーションのアーキテクチャ
DBIは、バックエンドで利用可能なデータベースから独立しています。 Oracle、MySQL、Informixなどのいずれで作業していても、DBIを使用できます。 これは、次のアーキテクチャ図から明らかです。
Ruby DBIの一般的なアーキテクチャは2つの層を使用します-
- データベースインターフェイス(DBI)層。 このレイヤーはデータベースに依存せず、通信するデータベースサーバーの種類に関係なく同じ方法で使用される一連の一般的なアクセス方法を提供します。
- データベースドライバー(DBD)レイヤー。 この層はデータベースに依存しています。異なるドライバーは、異なるデータベースエンジンへのアクセスを提供します。 MySQL用のドライバー、PostgreSQL用のドライバー、InterBase用のドライバー、Oracle用のドライバーなどがあります。 各ドライバーは、DBI層からの要求を解釈し、特定の種類のデータベースサーバーに適した要求にマッピングします。
前提条件
MySQLデータベースにアクセスするためのRubyスクリプトを作成する場合は、Ruby MySQLモジュールをインストールする必要があります。
このモジュールは、上記で説明したようにDBDとして機能し、https://www.tmtm.org/en/mysql/ruby/からダウンロードできます。
Ruby/DBIの入手とインストール
次の場所からRuby DBIモジュールをダウンロードしてインストールできます-
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があります。
- ユーザーID「testuser」とパスワード「test123」は、TESTDBにアクセスするように設定されています。
- Ruby Module 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 に保存されます。それぞれ。
最後に、公開する前に、データベース接続が閉じられ、リソースが解放されていることを確認してください。
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を使用して行われます
- すべてがうまくいったら、この操作を*コミット*します。
これらの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
# 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がある場合、最初にステートメントを準備し、ループ内で複数回実行する方が、ループを毎回実行するよりも効率的です。
読み取り操作
任意のデータベースに対する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
データベースからレコードを取得するためのショートカットメソッドは他にもあります。 興味がある場合は、リンクをたどってください:/ruby/ruby_dbi_fetching_results [Fetching the Result]そうでなければ、次のセクションに進んでください。
更新操作
データベースでのUPDATE操作とは、データベースですでに使用可能な1つ以上のレコードを更新することです。 以下は、SEXが「M」であるすべてのレコードを更新する手順です。 ここでは、すべての男性の年齢を1年ずつ増やします。 これには3つのステップがかかります-
- 必要な条件に基づいてSQLクエリを準備します。 これは、 prepare メソッドを使用して行われます。
- SQLクエリを実行して、データベースからすべての結果を選択します。 これは、 execute メソッドを使用して行われます。
- ステートメントハンドルを解放します。 これは finish メソッドを使用して行われます。
- すべてが正常に完了したら、この操作を*コミット*します。
#!/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操作が必要です。 以下は、AGEが20を超えるEMPLOYEEからすべてのレコードを削除する手順です。 この操作では、次の手順を実行します。
- 必要な条件に基づいてSQLクエリを準備します。 これは、 prepare メソッドを使用して行われます。
- SQLクエリを実行して、データベースから必要なレコードを削除します。 これは、 execute メソッドを使用して行われます。
- ステートメントハンドルを解放します。 これは finish メソッドを使用して行われます。
- すべてが正常に完了したら、この操作を*コミット*します。
#!/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 -トランザクションが完了するか、まったく何も起こりません。
- 一貫性-トランザクションは一貫した状態で開始し、システムを一貫した状態にしておく必要があります。
- 分離-トランザクションの中間結果は、現在のトランザクションの外部では見えません。
- 耐久性-トランザクションがコミットされると、システム障害が発生した後でも効果は持続します。
DBIは、トランザクションを_commit_または_rollback_するための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番目のアプローチでは、_transaction_メソッドを使用します。 これは、トランザクションを構成するステートメントを含むコードブロックを取得するため、より簡単です。 _transaction_メソッドはブロックを実行し、ブロックが成功するか失敗するかに応じて、_commit_または_rollback_を自動的に呼び出します-
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* メソッドを呼び出す簡単な例を次に示します。
dbh.commit
ロールバック操作
1つ以上の変更に満足せず、それらの変更を完全に元に戻したい場合は、 rollback メソッドを使用します。
*rollback* メソッドを呼び出す簡単な例を次に示します。
dbh.rollback
データベースの切断
データベース接続を切断するには、切断APIを使用します。
dbh.disconnect
データベースへの接続が切断メソッドを使用してユーザーによって閉じられた場合、未処理のトランザクションはすべてDBIによってロールバックされます。 ただし、DBIの実装の詳細に依存する代わりに、アプリケーションで明示的にコミットまたはロールバックを呼び出す方が適切です。
エラー処理
エラーには多くの原因があります。 いくつかの例は、実行されたSQLステートメントの構文エラー、接続障害、または既にキャンセルまたは終了したステートメントハンドルのフェッチメソッドの呼び出しです。
- DBIメソッドが失敗すると、DBIは例外を発生させます。 DBIメソッドはいくつかのタイプの例外を発生させる可能性がありますが、2つの最も重要な例外クラスは_DBI
- InterfaceError_と_DBI :: DatabaseError_です。
これらのクラスの例外オブジェクトには、err _、 errstr_、および_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 -このメソッドはステートメントハンドルを生成し、ブロックの最後で_finish_することをお勧めします。 ブロック内で、_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* は、コードブロックを取得し、それにステートメントハンドルを渡し、次のようにブロックの終わりに自動的に終了を呼び出します-
dbh.execute("SHOW DATABASES") do |sth|
puts "Databases: " + sth.fetch_all.join(", ")
end
DBI _transaction_メソッドは、上記で説明したコードブロックも使用します。
ドライバー固有の機能と属性
DBIを使用すると、データベースドライバーは、データベース固有の追加機能を提供できます。これは、任意のHandleオブジェクトの_func_メソッドを介してユーザーが呼び出すことができます。
ドライバー固有の属性がサポートされており、 [] = または [] メソッドを使用して設定または取得できます。
- __ DBD
- Mysqlは、次のドライバー固有の機能を実装します-
Sr.No. | Functions & Description |
---|---|
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に似ていますが、刺す代わりに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