要約
- MySQL 5.7.22 を入れていた PC に Homebrew で 8.0.11 をインストールしてしまい、Rails が動かなくなった
-
mysql2
のmysqlclient
ライブラリへの再リンクはbundle exec gem uninstall mysql2 && bundle install
で解決 -
mysql_upgrade -uroot
で MySQL サーバをアップグレードし、データベース側の問題も解決することで Rails が再び動き出した
発生事象
いつものようにbrew update && brew upgrade
した後、rails g
でとある Gem の初期ファイルを生成しようとしたところ、以下のエラーが発生。
/Users/hoge/rails/example/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require': dlopen(/Users/hoge/rails/example/vendor/bundle/ruby/2.5.0/gems/mysql2-0.5.1/lib/mysql2/mysql2.bundle, 9): Library not loaded: /usr/local/opt/mysql/lib/libmysqlclient.20.dylib (LoadError)
Referenced from: /Users/hoge/rails/example/vendor/bundle/ruby/2.5.0/gems/mysql2-0.5.1/lib/mysql2/mysql2.bundle
Reason: image not found - /Users/hoge/rails/example/vendor/bundle/ruby/2.5.0/gems/mysql2-0.5.1/lib/mysql2/mysql2.bundle
/usr/local/opt/mysql/lib/libmysqlclient.20.dylib
ファイルが見つからないため、エラーが発生しているようだ。
念のため、/usr/local/opt/mysql/lib
を確認してみる。
$ ls -l /usr/local/opt/mysql/lib
total 22424
-r--r--r-- 1 hoge admin 5423044 6 15 12:22 libmysqlclient.21.dylib
-r--r--r-- 1 hoge admin 6041280 4 8 16:02 libmysqlclient.a
lrwxr-xr-x 1 hoge admin 23 4 8 16:02 libmysqlclient.dylib -> libmysqlclient.21.dylib
-r--r--r-- 1 hoge admin 9624 4 8 16:02 libmysqlservices.a
drwxr-xr-x 3 hoge admin 102 6 15 12:22 pkgconfig
drwxr-xr-x 91 hoge admin 3094 4 8 16:02 plugin
確かにlibmysqlclient.20.dylib
がなく、代わりにlibmysqlclient.21.dylib
が存在している。
brew upgrade
でmysqlclient
がアップデートされてしまったためだろうか。
対処その1:Gem に最新のmysqlclient
ライブラリをリンクさせる
調べたところ、libmysqlclient.20.dylib
へのシンボリックリンクを/usr/local/opt/mysql/lib
に設置すれば良さそうだ。
libmysqlclient.20.dylib
を探してみる。
$ find /usr -name 'libmysqlclient.20.dylib'
/usr/local/Cellar/mysql/5.7.22/lib/libmysqlclient.20.dylib
find: /usr/sbin/authserver: Permission denied
Homebrew でインストールした MySQL ライブラリが残っていた。
その後もう少し調べたところ、僕の PC には MySQL 5.7.22 と MySQL 8.0.11 がインストールされており、5.7.22 はlibmysqlclient.20.dylib
、8.0.11 はlibmysqlclient.21.dylib
を使用しているらしいということが分かった。
シンボリックリンクを設置する方法はあまり美しくないし、今後は MySQL 8.0 以降が使われていくだろうから、できれば最新のライブラリを使うようにしたい。
そうなると Gem を更新し、mysqlclient
ライブラリを再リンクする必要がありそう。
bundle doctor
によると、今回問題になっている Gem はmysql2
のみのようだ。
$ bundle doctor
The Gemfile's dependencies are satisfied
The following gems are missing OS dependencies:
* mysql2: /usr/local/opt/mysql/lib/libmysqlclient.20.dylib
mysql2
を個別にアンインストール→再インストールしてみる。
$ bundle exec gem uninstall mysql2
Successfully uninstalled mysql2-0.5.1
$ bundle install
(略)
Fetching mysql2 0.5.1
Installing mysql2 0.5.1 with native extensions
(略)
Bundle complete! 29 Gemfile dependencies, 118 gems now installed.
Bundled gems are installed into `./vendor/bundle`
$ bundle doctor
The Gemfile's dependencies are satisfied
No issues found with the installed bundle
リンクの問題は解消されたので、もう一度rails g
を実行してみると、今度は別のエラーが。
/Users/hoge/rails/example/vendor/bundle/ruby/2.5.0/gems/mysql2-0.5.1/lib/mysql2/client.rb:131:in `_query': Mysql2::Error::ConnectionError: Access denied for user 'example'@'localhost' (using password: YES): SELECT table_name FROM information_schema.tables WHERE table_schema = database() (ActiveRecord::StatementInvalid)
調べてみると今度は MySQL のアップグレードが必要らしい。
対処その2:MySQL サーバのアップグレード
まずはアップグレードに失敗した時のためのバックアップを取ろうとしたが、エラーが発生。
$ mysqldump -uroot --databases example_development example_test --column-statistics=0 --single-transaction > ./tmp/db_backup.dump
Password:
mysqldump: Error: 'The user specified as a definer ('mysql.infoschema'@'localhost') does not exist' when trying to dump tablespaces
MySQL 5.7 クライアントからデータベース操作しようとしても上記のようなエラーが出る。
(つまり対処その1でlibmysqlclient.20.dylib
を継続利用しようとしても同様のエラーが発生したはず)
仕方ないので、成功するかどうか分からないがアップグレードをかける。
$ mysql_upgrade -uroot
Checking if update is needed.
Checking server version.
Running queries to upgrade MySQL server.
Upgrading system table data.
Checking system database.
mysql.columns_priv OK
mysql.component OK
mysql.db OK
mysql.default_roles OK
mysql.engine_cost OK
mysql.func OK
mysql.general_log OK
mysql.global_grants OK
mysql.gtid_executed OK
mysql.help_category OK
mysql.help_keyword OK
mysql.help_relation OK
mysql.help_topic OK
mysql.innodb_index_stats OK
mysql.innodb_table_stats OK
mysql.ndb_binlog_index OK
mysql.password_history OK
mysql.plugin OK
mysql.procs_priv OK
mysql.proxies_priv OK
mysql.role_edges OK
mysql.server_cost OK
mysql.servers OK
mysql.slave_master_info OK
mysql.slave_relay_log_info OK
mysql.slave_worker_info OK
mysql.slow_log OK
mysql.tables_priv OK
mysql.time_zone OK
mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
mysql.user OK
Found outdated sys schema version 1.5.1.
Upgrading the sys schema.
Checking databases.
example_development.ar_internal_metadata OK
example_development.hogehoge OK
example_development.schema_migrations OK
example_test.ar_internal_metadata OK
example_test.hogehoge OK
example_test.schema_migrations OK
sys.sys_config OK
Upgrade process completed successfully.
Checking if update is needed.
なんとか成功した。
その後rails g
を実行したところ、エラーは発生せず、目的の初期ファイルが生成された。
また、データベース操作系のタスクも実行し、エラーが発生しないことを確認した。
備考
MySQL 8.0.11 は本当に今回のbrew update && brew upgrade
の時に自動でインストールされてしまったものなのだろうか?
メジャーアップデートで大幅な変更が施されているそうなので、brew upgrade
で勝手にメジャーバージョンアップするのだとしたらかなり問題になりそうなのだが…。
それとも以前に自分が最新バージョンを試してみたくなって 8.0 系を手動でインストールしたのだろうか?
それで MySQL サーバの再起動によって今回 5.7 → 8.0 に意図せず切り替わってしまったとか…。
記憶は定かではない。