ぎょーぼのぶろぐ

IT系の話を書いていくブログです。今はRubyの勉強中。

【Ruby】MySQL に接続してみる その2

前置き

【Ruby】MySQL に接続してみる その1 - ぎょーぼのぶろぐ の記事の続きです。

前回、MySQL側のデータの準備を行いましたので、今回は、Ruby側から MySQL に接続して、データを参照してみます。

MySQL に接続するための gem をインストールする。

Ruby から MySQL へ接続するためには、Ruby用の MySQL クライアントが必要です。

2020/11/18 時点で、いろいろ種類があるみたいですが、「MySQL2」という gem が最も使われているようなので、こちらを使用します。

  • 一番それっぽい名前の「MySQL」gem は、エラーでインストールできませんでした。gem のアップデートも 2013年でストップしているので、皆さん「MySQL2」へ移っているものと思われます。

「MySQL2」gem のインストールは、gem install コマンドを使えば OK です。

> gem install mysql2

引数なしでインストールすると、バージョンは 「mysql2 (0.5.3 x64-mingw32)」となりました。 *1 ・・・メジャーバージョンが 0 なのはなんでだろ?

Ruby コードから、MySQL のデータを取得してみる

「Mysql2」 gem の使い方は、製作者の方が github 上に公開しています。

GitHub - brianmario/mysql2: A modern, simple and very fast Mysql library for Ruby - binding to libmysql

こちらを参考に、テーブルのデータを取得して表示するだけの、単純な Ruby のコードを書いてみます。手順としては、、、

  1. mysql2 を require する。
  2. Mysql2::Client.new でコネクションオブジェクトを生成する。
  3. コネクションオブジェクトの query メソッドに SQL文を送って、結果を取得する。
  4. 結果を表示

実際のコードは下のような感じです。ファイル名は「mysql_test.rb」です。

require 'mysql2'

client = Mysql2::Client.new(host: 'localhost', username: 'gyobo', password: 'password', encoding: 'utf8mb4', database: 'world')

results= client.query('select * from country;')

results.each do |row|
    puts "ID : #{row["id"]}, Name: #{row["name"]}"
end

これで実行してみると・・・下のようにエラーが出てしまいます。

>ruby mysql_test.rb
Traceback (most recent call last):
        3: from mysql_test.rb:3:in `<main>'
        2: from mysql_test.rb:3:in `new'
        1: from C:/Ruby/Ruby26-x64/lib/ruby/gems/2.6.0/gems/mysql2-0.5.3-x64-mingw32/lib/mysql2/client.rb:90:in `initialize'
 (Mysql2::Error)64/lib/ruby/gems/2.6.0/gems/mysql2-0.5.3-x64-mingw32/lib/mysql2/client.rb:90:in `connect': Authentication plugin 'caching_sha2_password' cannot be loaded: ?w?肳?ꂽ???W???[??????????܂???B

エラーの原因:「mysql2」gem が caching_sha2_password に対応してないから

ポイントは、エラー文言の中の「Authentication plugin 'caching_sha2_password' cannot be loaded」の部分です。認証プラグイン'caching_sha2_password'がロードできない・・・

MySQL は、ユーザー認証の際に「認証プラグイン」というのを使うそうです。MySQL 5 のときは「mysql_native_password」がデフォルトだったのですが、MySQL 8 になってから「caching_sha2_password」というのが追加され、ユーザーの新規作成時、認証プラグインを指定しない場合は、デフォルトで「caching_sha2_password」となるそうです。そして、、、MySQLクライアントで「caching_sha2_password」に対応しているものが Ruby ではまだ無い(2020年11月現在)、、、ということみたいです。

「caching_sha2_password」に対応しているMySQLクライアントは、以下のリンク先で確認できます。

MySQL :: MySQL 8.0 Reference Manual :: 2.11.4 Changes in MySQL 8.0

このため、Ruby から MySQL 8 へ接続するためには、MySQL に接続するユーザーの認証プラグインをあらかじめ、「mysql_native_password」にしておく必要があります。。。

というわけで、MySQL にログインして、ユーザーの認証プラグインを「mysql_native_password」に変更します。

mysql> SELECT user, plugin FROM mysql.user WHERE user='gyobo';
+------------------+-----------------------+
| user             | plugin                |
+------------------+-----------------------+
| gyobo            | caching_sha2_password |
+------------------+-----------------------+
1 rows in set (0.00 sec)

mysql> ALTER USER gyobo@localhost IDENTIFIED WITH mysql_native_password BY 'password';
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT user, plugin FROM mysql.user WHERE user='gyobo';
+------------------+-----------------------+
| user             | plugin                |
+------------------+-----------------------+
| gyobo            | mysql_native_password |
+------------------+-----------------------+
1 rows in set (0.00 sec)

こうして再度、実行してみると、、、

>ruby mysql_test.rb
ID : 1, Name: 日本
ID : 2, Name: アメリカ
ID : 3, Name: イギリス

データを取得することができました。

補足?蛇足?

ネットでいろいろ調べてみると、MySQL でユーザーを作成する際のデフォルトの認証プラグインを「mysql_native_password」に変更したらいい、という記事も見かけました。が、個人的にはそれはしない方がいいと思います。

理由は、「caching_sha2_password」 の方が、「mysql_native_password」よりもセキュリティ面では良いらしいから。

基本は、「caching_sha2_password」を使うようにして、今回のように「caching_sha2_passwordが対応してないから使えない」という場合に、必要な範囲で「mysql_native_password」に変更するようにすべき、と思われます。

*1:2020年11月18日現在です。