English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
この章では、Rubyでデータベースにアクセスする方法について説明します。Ruby DBI モジュールは、Perl DBIモジュールに似たデータベースに依存しないインターフェースをRubyスクリプトに提供します。
DBI(Database independent interface)は、Rubyがデータベースに依存しないインターフェースを代表しており、Rubyコードとベースデータベース間に抽象レイヤーを提供します。データベースの切り替えを簡単に実現できるように、一連のメソッド、変数、規約を定義し、データベースに依存しない一貫したデータベースインターフェースを提供します。
DBI は以下と連携できます:
ADO (ActiveX Data Objects)
DB2
Frontbase
mSQL
MySQL
ODBC
Oracle
OCI8 (Oracle)
PostgreSQL
Proxy/Server
SQLite
SQLRelay
DBI は後で利用可能なすべてのデータベースに独立しています。Oracle、MySQL、Informixを使用している場合でも、DBIを使用できます。以下のアーキテクチャ図はこれを明確に示しています。
Ruby DBI の一般的なアーキテクチャは、2つのレベルを使用しています:
データベースインターフェース(DBI)レベル。このレベルはデータベースに依存しておらず、データベースサーバーのタイプに関係なく公共のアクセスメソッドを提供します。
データベースドライバ(DBD)レベル。このレベルはデータベースに依存しており、異なるドライバは異なるデータベースエンジンへのアクセスを提供します。MySQL、PostgreSQL、InterBase、Oracleなどはそれぞれ異なるドライバを使用します。各ドライバは DBI レベルからのリクエストを解釈し、それを特定のデータベースサーバーのリクエストにマッピングします。
MySQL データベースにアクセスする Ruby スクリプトを書く場合、まず Ruby 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は約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
このモジュールは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というフィールドがあります。
ユーザーID「testuser」およびパスワード「test」を設定123「」でTESTDBにアクセス
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 "エラーが発生しました" puts "エラーコード: #{e.err}" puts "エラーメッセージ: #{e.errstr}" ensure # サーバーとの接続を切断 dbh.disconnect if dbh end
このスクリプトを実行すると、Linuxマシン上に以下の結果が生成されます。
Server version: 5.0.45
データソースが接続に含まれている場合、データベースハンドル(Database Handle)が返され、 dbh 内に保存され、後で使用されるために残されます。さもなければ、 dbh NULL値に設定されます。e.err および e::errstr それぞれエラーコードとエラーストリングを返します。
最後に、このプログラムから退出する前に、データベース接続を閉じ、リソースを解放してください。
データベーステーブルにレコードを作成したい場合、INSERT操作を使用する必要があります。
データベース接続が確立されると、それを使用する準備ができます。 do メソッドまたは prepare および execute メソッドを使用してテーブルを作成したり、データ表にデータを挿入したりします。
行を返さない文は、 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 "エラーが発生しました" puts "エラーコード: #{e.err}" puts "エラーメッセージ: #{e.errstr}" dbh.rollback ensure # サーバーとの接続を切断 dbh.disconnect if dbh end
DBIの prepare および execute メソッドを使用してRubyコード内でSQL文を実行します。
レコードを作成する手順は以下の通りです:
INSERT文を含むSQL文を準備します。これはステートメントを用いて行われます。 prepare 方法を使用して行います。
SQLクエリを実行し、データベースからすべての結果を選択します。これは以下を使用して行われます execute 方法を使用して行います。
文のハンドルを解放します。これは、以下を使用して行われます。 finish APIを使用して完了します。
すべてが順調に進む場合、 commit この操作を行わない場合、または以下の方法で行うことができます。 rollback 取引を完了します。
以下はこれら二つの方法の文法です:
sth = dbh.prepare(statement) sth.execute ... 0または複数のSQL操作... sth.finish
これらの二つの方法を使用してデータを伝達することができます。 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 "エラーが発生しました" puts "エラーコード: #{e.err}" puts "エラーメッセージ: #{e.errstr}" dbh.rollback ensure # サーバーとの接続を切断 dbh.disconnect if dbh end
複数のINSERTを使用する場合、一度にクエリを準備し、ループ内で複数回実行することで、ループごとにdoを呼び出すよりも効率的です。
データベースのREAD操作とは、データベースから有用な情報を取得することを指します。
データベース接続が確立されると、データベースをクエリする準備ができます。以下を使用できます do メソッドまたは prepare および execute メソッドを使用してデータベーステーブルから値を取得します。
レコードを取得する手順は以下の通りです:
必要な条件に基づいてSQLクエリを準備します。これは以下を使用して行われます。 prepare 方法を使用して行います。
SQLクエリを実行し、データベースからすべての結果を選択します。これは以下を使用して行われます execute 方法を使用して行います。
結果を順次取得し、これらの結果を出力します。これは以下を使用して行われます 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 "エラーが発生しました" puts "エラーコード: #{e.err}" puts "エラーメッセージ: #{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
データベースのUPDATE操作とは、データベース内の1件または複数の既存のレコードを更新することを指します。以下の例では、SEXが'M'のすべてのレコードを更新します。ここでは、すべての男性のAGEを一歳増やします。これは3つのステップに分けられます:
必要な条件に基づいてSQLクエリを準備します。これは以下を使用して行われます。 prepare 方法を使用して行います。
SQLクエリを実行し、データベースからすべての結果を選択します。これは以下を使用して行われます execute 方法を使用して行います。
文のハンドルを解放します。これは、以下を使用して行われます。 finish 方法を使用して行います。
すべてが順調に進む場合、 commit この操作を行わない場合、または以下の方法で行うことができます。 rollback 取引を完了します。
#!/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 "エラーが発生しました" puts "エラーコード: #{e.err}" puts "エラーメッセージ: #{e.errstr}" dbh.rollback ensure # サーバーとの接続を切断 dbh.disconnect if dbh end
データベースからレコードを削除する場合、DELETE操作を使用する必要があります。以下の例では、AGEが 20のすべてのレコード。この操作の手順は以下の通りです:
必要な条件に基づいてSQLクエリを準備します。これは以下を使用して行われます。 prepare 方法を使用して行います。
SQLクエリを実行して、データベースから必要なレコードを削除します。これは以下を使用して行われます。 execute 方法を使用して行います。
文のハンドルを解放します。これは、以下を使用して行われます。 finish 方法を使用して行います。
すべてが順調に進む場合、 commit この操作を行わない場合、または以下の方法で行うことができます。 rollback 取引を完了します。
#!/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 "エラーが発生しました" puts "エラーコード: #{e.err}" puts "エラーメッセージ: #{e.errstr}" dbh.rollback ensure # サーバーとの接続を切断 dbh.disconnect if dbh end
取引は取引の一致性を確保するメカニズムです。取引は以下の四つの属性を持たなければなりません:
原子性(Atomicity):取引の原子性は、取引中に含まれるプログラムがデータベースの論理的な作業ユニットとして機能し、データに対する変更操作は全て実行されるか、全く実行されないことを意味します。
一貫性(Consistency):取引の一致性は、取引を実行する前におよび実行後にデータベースが一貫性の状態にある必要があります。データベースの状態がすべての完全性制約を満たす場合、データベースは一貫しているとされます。
隔離性(Isolation):取引の隔離性は、並行する取引が相互に隔離されていることを意味し、すなわち、一つの取引内の操作および操作中のデータは、他の変更を試みる取引から隔離されなければなりません。
持続性(Durability):取引の持続性は、システムやメディアが故障した場合に、既にコミットされた取引の更新が失われないことを確実にする意味です。すなわち、一旦取引がコミットされると、データベース中のデータに対する変更は永続的で、どのデータベースシステムの故障にも耐えうるべきです。持続性はデータベースのバックアップとリカバリによって保証されます。
DBI は取引を実行するための二つの方法を提供しています。一つは、 commit または rollback 方法、取引をコミットまたはロールバックするために使用されます。他には、 transaction 方法、取引を実行するために使用できます。次に、これらの簡単な取引の実現方法について説明します:
第一种方法使用 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
第二种方法使用 transaction 方法。この方法は比較的簡単で、取引文を構成するコードブロックを持つ必要があります。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 メソッドの簡単な例。
dbh.commit
もし何かまたは何かの変更に不満があり、これらの変更を完全に元に戻したい場合は、 rollback メソッドの呼び出し例です。
以下は、 rollback メソッドの簡単な例。
dbh.rollback
データベース接続を切断するには、disconnect APIを使用してください。
dbh.disconnect
ユーザーがdisconnectメソッドを使用してデータベース接続を閉じた場合、DBIはすべての未完了のトランザクションをロールバックします。ただし、DBIの実装の詳細に依存することなく、アプリケーションは明示的にcommitやrollbackを呼び出すことができます。
多くの異なるエラーソースがあります。例えば、SQL文の構文エラー、接続失敗、キャンセルされたまたは完了したステートメントハンドルに対するfetchメソッドの呼び出しなどです。
DBIのメソッドが失敗すると、DBIは例外を投げます。DBIのメソッドはどんな種類の例外も投げることができますが、最も重要な2つの例外クラスは DBI::InterfaceError および DBI::DatabaseError。
これらのクラスのExceptionオブジェクトには err、errstr および state 3つの属性があり、それぞれエラーコード、説明的なエラーストリング、標準のエラーコードを表しています。属性の詳細は以下の通りです:
err:発生したエラーの整数表示を返します。DBDがサポートしていない場合は、nilを返します。 nil。例えば、Oracle DBDは以下のように返します ORA-XXXX エラーメッセージの数字部分。
errstr:発生したエラーの文字列表現を返します。
state:発生したエラーのSQLSTATEコードを返します。SQLSTATEは5文字の長さの文字列です。多くのDBDはそれをサポートしていないため、nilを返します。
上の例で見た以下のコード:
rescue DBI::DatabaseError => e puts "エラーが発生しました" puts "エラーコード: #{e.err}" puts "エラーメッセージ: #{e.errstr}" dbh.rollback ensure # サーバーとの接続を切断 dbh.disconnect if dbh end
スクリプトの実行中にスクリプトの実行内容に関するデバッグ情報を取得するには、トレースを有効にすることができます。これには、まずdbiをダウンロードする必要があります。/traceモジュールをインストールし、コントロールトラッキングモードと出力先の trace メソッド:
require "dbi/trace" .............. trace(mode, destination)
modeの値は0(off)、1、2 または 3、destinationの値はIOオブジェクトであるべきです。デフォルト値は 2 およびSTDERR。
ハンドルを生成する方法がいくつかあります。これらの方法はコードブロックを通じて呼び出されます。コードブロックを持ち、それにメソッドを渡すコードブロックの利点は、コードブロックが終了するとハンドルが自動的にクリアされることです。以下の例がこの概念を理解するのに役立ちます。
DBI.connect :メソッドはデータベースハンドルを生成し、ブロックの終わりに呼び出すことを推奨します。 disconnect を使用してデータベースを切断します。
dbh.prepare :メソッドはステートメントハンドルを生成し、ブロックの終わりに呼び出すことを推奨します。 finish。ブロック内では、 execute メソッドを使用して文を実行します。
dbh.execute :このメソッドはdbh.prepareに似ていますが、dbh.executeはブロック内でexecuteメソッドを呼び出す必要はありません。ステートメントハンドルは自動的に実行されます。
DBI.connect コードブロックを持ち、それにデータベースハンドルを渡し、ブロックの終わりに自動的にハンドルが切断されます。
dbh = DBI.connect("DBI:Mysql:TESTDB:localhost", "testuser", "test123) do |dbh|
dbh.prepare コードブロックを持ち、それにステートメントハンドルを渡し、ブロックの終わりに自動的にfinishが呼び出されます。
dbh.prepare("SHOW 、DATABASES") do |sth| sth.execute puts "データベース: " + sth.fetch_all.join("、") end
dbh.execute コードブロックを持ち、それにステートメントハンドルを渡し、ブロックの終わりに自動的にfinishが呼び出されます。
dbh.execute("SHOW 、DATABASES") do |sth| puts "データベース: " + sth.fetch_all.join("、") end
DBI transaction メソッドもコードブロックを持つことができ、これは前の章で説明されています。
DBIは、データベースドライバープログラムに追加の特定のデータベースの関数を提供し、これらの関数はユーザーがどんなHandleオブジェクトでも呼び出すことができます。 func メソッドを使用して呼び出します。
を使用して呼び出します。 []= または [] メソッドは特定のドライバの属性を設定または取得できます。
DBD::Mysql は以下の特定のドライバーの関数を実装しています:
番号 | 関数および説明 |
---|---|
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) => Stringb> データベースの現在の状態を返します。 |
12 | dbh.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 "エラーが発生しました" puts "エラーコード: #{e.err}" puts "エラーメッセージ: #{e.errstr}" ensure dbh.disconnect if dbh end
これは以下の結果を生成します:
5.0.45 50045 ローカルホスト via UNIX ソケット 10 5.0.45 150621 アップタイム: 384981 スレッド: 1 質問: 1101078 遅いクエリ: 4 \ オープン: 324 フラッシュテーブル: 1 オープンテーブル: 64 \ 秒あたりクエリ平均: 2.860