今回は、RubyプログラムからMySQLの操作がしたい場合に、mysql2
というライブラリを利用してMySQLへアクセスする方法を紹介したいと思います。mysql2
はRuby on Railsでも利用されているライブラリで、RailsのActiveRecordと組み合わせて利用される事も多いですが、今回はRubyのプログラムからアクセスする方法を紹介したいと思います。
検証環境
第10回 yum, rpmインストールにおけるMySQL 5.6とMySQL 5.7の違い で紹介されたyumリポジトリーを使用したインストールを利用しています。また、MySQLのバージョンは5.7.22を使用しています。つい先日(2018年4月19日) 、MySQ L8.0もGAになりましたが、今回は5.7を利用して説明を行っていきます。
mysql2をインストールする際に、mysqlのヘッダファイルが必要となるため、追加でsudo yum install mysql-community-devel -y
を実行しておきましょう。これを忘れると次のmysql2をインストール中にエラーが出て途中で停止してしまいます。
Rubyのインストールをする
CentOSでRubyをインストールする方法としては、大まかに分けて4種類が考えられます。
rbenvとruby-buildを利用してインストールする
rvmを利用してインストールする
yumを利用してインストールする
自力でビルドをする
今回は手軽に試して行きたいので、yumでrubyをインストールします。しかし、yumでインストールされるRubyは2.0系とかなり古いので、実際に開発や本番で利用する際には、rbenvやrvmを利用して、なるべく最新のrubyを使うようにしましょう。
$ sudo yum install -y ruby ruby-devel
以上のコマンドでrubyをインストールすることができます。
mysql2をインストールする
Rubyでライブラリをインストールするには、RubyGemsというライブラリを管理する仕組みを利用します。とりあえず試してみたい場合は、以下のようにgem install
コマンドを使ってmysql2をインストールしてみましょう。
$ sudo gem install mysql2
正しくインストールができているかは、以下のようにirbという対話的なインタープリタを使うことで確認することができます。この例のようにrequire 'mysql2'
を実行した時にtrueが返ってきたら、正しくインストールが完了しています。この時にLoadError: cannot load such file -- mysql2
のようなメッセージが出た場合は、mysql2のインストールに失敗しているので、もう一度最初から試してみてください。
$ irb
irb(main):001:0> require 'mysql2'
=> true
gem install
でインストールした場合に、インストールを行った時期によって複数バージョンがインストールされてしまうことがあります。複数のバージョンが混在するような場合に、どのバージョンを使っているかを指定する仕組みとして、bundler
があります。こちらを使ってインストールを行う場合は以下のようにコマンドを実行してください。また、bundleを使った場合はirbを実行する時に、単にirb
と打つのではなく、bundle exec irb
とコマンドがちょっとだけ変わるのに注意をしてください。
$ gem install bundler
$ bundle init
$ ls
Gemfile
$ echo 'gem mysql2' > Gemfile
$ bundle install
$ bundle exec irb
irb(main):001:0> require 'mysql2'
=> true
bundle install
を行った時点で生成されているGemfile.lock
ですが、こちらに使用するバージョン情報などが書かれています。そのため、別のPCなどへソースコードを持っていった場合にも、同じバージョンをインストールしてすぐに利用することができるようになります。Gemfile.lock
の中身は以下のようになっており、mysql2のバージョン情報(今回は0.5.1)も含めて記録されていることがわかります。
GEM
remote: https://rubygems.org/
specs:
mysql2 (0.5.1)
PLATFORMS
ruby
DEPENDENCIES
mysql2
BUNDLED WITH
1.16.1
mysql2を使ってMySQLに接続をする
rubyのインストールとmysql2のインストール、お疲れさまでした。ここからは、インストールしたmysql2を使ってMySQLに接続をするプログラムを書いてみます。
require 'mysql2'
client = Mysql2::Client.new(host: "localhost", username: "root", password: '', database: 'mysql')
上記のように、MySQL2::Client
クラスを使って接続を行います。引数にrubyのハッシュ値を渡すことで、接続情報を加えることができます。よく使うオプションについて、以下の表にまとめました。
オプション
オプションの意味
host
接続先のホスト情報
username
接続に使用するユーザ名
password
接続に使用するパスワード
database
接続するデータベース
socket
unixドメインソケットの情報
port
接続先のポート情報(デフォルトは3306)
encoding
文字エンコーディングの指定
これ以外でどのようなオプションがあるのか気になる方は、GitHub上のReadmeに書かれているConnection optionsの項 を確認してみてください。
SQLを実行してみる
接続することができたので、続けてSQLを実行してみようと思います。SQLを実行するには、query
メソッドにSQL文字列を渡す事で実行されます。今回は文字列を結合する方式で行っているため、文字列をescapeして問題とならないように修正して結合しています。
$ cat main.rb
require 'mysql2'
client = Mysql2::Client.new(host: "localhost", username: "root", password: '', database: 'mysql')
escaped = client.escape('performance_schema')
results = client.query("SELECT Db FROM db WHERE Db = '#{escaped}'")
results.each do |row|
puts row
puts row['Db']
end
$ bundle exec ruby main.rb
{"Db"=>"performance_schema"}
performance_schema
上記のコードを実行するとSELECTが実行されて、Dbカラムがperfomance_schemaになっている要素が取得できていることがわかります。
プリペアードステートメントを使ってみる
さて、前項ではエスケープをした文字列を結合する形でSQLを組み立てました。しかし、この方法だとエスケープに漏れがあった場合に、SQLインジェクションという恐ろしい脆弱性を引き起こしてしまう可能性があります。その脆弱性を防ぐために、プリペアードステートメントという仕組みがあります。ここではその使い方を紹介していこうと思います。
$ cat main2.rb
require 'mysql2'
client = Mysql2::Client.new(host: "localhost", username: "root", password: '', database: 'mysql')
statement = client.prepare('SELECT Db FROM db WHERE Db = ?')
results = statement.execute('performance_schema')
results.each do |row|
puts row
puts row['Db']
end
$ bundle exec ruby main2.rb
{"Db"=>"performance_schema"}
performance_schema
今回はprepare
メソッドとexecute
メソッドを使用しています。prepare
メソッドでプリペアードステートメントを定義しています。SQL中で、プログラムから指定を行いたい箇所に?
と書きます。
その後、execute
メソッドで実行しています。引数にはプログラムからSQLに与えたい文字列を渡しています。こちらもquery
メソッドで実行したときと同様に、Dbカラムがperfomance_schemaになっている要素が取得できていることがわかります。
まとめ
今回は、mysql2
というライブラリを利用して、RubyのプログラムからMySQLに接続する基本的な方法を紹介しました。このライブラリを利用すると、簡単にプログラムからMySQLを利用できるようになります。ちょっとした変換などを行いたい場合に、SQLだけで頑張るのは辛いときもあります。そんな時に、この方法を使えばRubyとSQLを組み合わせて簡単に実現できるようになるので、試してみてはいかがでしょうか。