Homebrew で MySQL を 5.7.22 から 8.0.11 にバージョンアップしたら Rails が動かなくなったので対処する

# 要約
- 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 の初期ファイルを生成しようとしたところ、以下のエラーが発生。

```console:console
/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`を確認してみる。

```console:console
$ 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`がアップデートされてしまったためだろうか。

# 対処その１：Gem に最新の`mysqlclient`ライブラリをリンクさせる

調べたところ、`libmysqlclient.20.dylib`へのシンボリックリンクを`/usr/local/opt/mysql/lib`に設置すれば良さそうだ。
`libmysqlclient.20.dylib`を探してみる。

```console:console
$ 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`のみのようだ。

```console:console
$ 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`を個別にアンインストール→再インストールしてみる。

```console:console
$ 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`を実行してみると、今度は別のエラーが。

```console:console
/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 のアップグレードが必要らしい。

# 対処その２：MySQL サーバのアップグレード

まずはアップグレードに失敗した時のためのバックアップを取ろうとしたが、エラーが発生。

```console:console
$ 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 クライアントからデータベース操作しようとしても上記のようなエラーが出る。
（つまり対処その１で`libmysqlclient.20.dylib`を継続利用しようとしても同様のエラーが発生したはず）

仕方ないので、成功するかどうか分からないがアップグレードをかける。

```console:console
$ 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 に意図せず切り替わってしまったとか…。
記憶は定かではない。