はじめに
RDSのMySQL5.7がサポート終了に伴い、MySQL8.0へのバージョンアップが必要になりました。
その際に調べたことについて書いていこうと思います。
環境
- 仮装環境
- Docker
- 言語&フレームワーク
- PHP8系
- Laravel10
- DB
- MySQL5.7
- MySQL8.0
アップグレード時の注意点
1. デフォルト文字コードの変更
MySQL8.0から、デフォルトの文字コードがutf8mb4になった。
絵文字や幾つかの特殊な文字を保存できるようになった反面、今まで使用していた文字コードと変わってしまう。
加えて、defaultのcharacter setで設定していた人は、 今まで使っていた文字コードと変わってしまうので、自分で以前使っていた文字コードを指定する必要がある。
2. 予約語の追加
MySQL8.0で幾つか予約語が追加された。
それにより今までのSQL文やカラム名で使用できていた単語が予約語に引っかかり構文エラーなどが生じる。
- CUBE
- EMPTY
- JSON_TABLE
- LAST_VALUE
- RANK
etc
詳しくは「公式サイト」を参照
3. 変数、関数の削除と追加
クエリの中で使える変数や関数にも変更があった。
削除されたものを使用している場合、実行されなくなる。
- 変数(廃止)
-
query_cache_size, query_cache_type
- クエリキャッシュはMySQL 8.0で完全に削除された
-
secure_auth
- この変数は廃止され、MySQL 8.0以降ではセキュアなパスワード認証は常に必須となった
-
old_passwords
- MySQLの旧バージョンのパスワードハッシュ方式に関連していたが、MySQL 8.0では削除された
-
query_cache_size, query_cache_type
- 関数(廃止)
-
PASSWORD()
- ユーザーパスワードのハッシュを生成するために使われていたが、廃止された
-
ENCRYPT()
- この関数は暗号化のためのものだったが、他のより安全な関数やアルゴリズムに置き換えられた
-
DES_ENCRYPT(), DES_DECRYPT()
- これらの関数も同様に暗号化のためのものだったが、MySQL 8.0で削除された
-
PASSWORD()
- 関数(追加)
-
JSON_ARRAYAGG()
- JSON配列として集約された結果セットの値を返す
-
JSON_OBJECTAGG()
- キーと値のペアを使用して、集約された結果セットからJSONオブジェクトを作成する
-
JSON_TABLE()
- JSONドキュメントを関係データの行と列に変換、通常のテーブルのようにJOINやクエリを実行できる
-
JSON_OVERLAPS()
- 2つのJSONドキュメントが共通の要素やキーを持っているかどうかを判定する
-
JSON_MERGE_PATCH()
- 2つのJSONドキュメントを統合するが、
JSON_MERGE_PRESERVE()
とは異なり、2つ目のオブジェクトでNULLの値を持つキーは最初のオブジェクトから削除される
- 2つのJSONドキュメントを統合するが、
-
JSON_STORAGE_SIZE()
- JSONドキュメントがディスク上で消費するバイト数を返す
-
JSON_STORAGE_FREE()
- JSONドキュメント内で未使用のスペースのバイト数を返す
-
JSON_KEYS()
- JSONオブジェクトのキーの配列を返す
etc
- JSONオブジェクトのキーの配列を返す
-
JSON_ARRAYAGG()
詳しくは「公式サイト」を参照
4. デフォルトの認証プラグインの変更
MySQL8.0からデフォルトの認証プラグインとしてcaching_sha2_password
が導入された。
旧バージョンのmysql_native_password
よりもセキュリティが向上している。
これにより、アプリケーションやライブラリが新しい認証プラグインをサポートしているかどうかを確認し、必要に応じて更新や設定変更を行う。
アップグレード手順
-
docker-compose.ymlの修正
Laravel以外(SQLで直接)から新規でテーブルとカラムを追加する可能性がない場合services: db: - image: mysql:5.7 + image: mysql:8.0
Laravel以外(SQLで直接)から新規でテーブルとカラムを追加する可能性がある場合
my.cnfファイルの作成
下記の内容を記載したmy.cnf
ファイルをdockerディレクトリへ格納する。[mysqld] character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci
docker-compose.ymlの修正
// 既存 services: db: - image: mysql:5.7 + image: mysql:8.0 + volumes: + - ./_docker/my.cnf:/etc/mysql/my.cnf
2. コンテナ再作成
docker-compose down
で既存のコンテナをストップさせてからdocker-compose up -d
の実行を行う。
3. テスト実行
問題なく動くか確認する。
検証時に行った手順
アプリケーション側の自動テストが充実してたこともあり、アップグレード時の注意点を頭に入れつつとりあえず、アップグレードすることにしました。
- docker-compose.ymlの修正
services: db: - image: mysql:5.7 + image: mysql:8.0
2. docker-compose up -d
の実行
既存のコンテナを削除してdocker-compose up -d
の実行を行う。
3. マイグレーションの実行
現在の環境がPHP8系、Laravel10ということもあり、caching_sha2_password
認証プラグインに対応している。(PHP7.4以降から対応されている)
もしも古いバージョンの場合はこの段階でエラー発生します。
その場合、前項にも挙げた「デフォルトの認証プラグインの変更」の影響があるので、バージョンアップの前に下記の手順を行う。
3-1. MySQL5.7のdefault-authentication-pluginを確認
何も行わず、MySQL8.0へバージョンを上げると
MySQL8.0
3-2. my.cnfを追加とdocker-compose.ymlの修正
my.cnf
とは、MySQLの設定ファイルで、パラメータの設定などをする際に用いられる。
詳しくは「公式サイト」を参照
下記の内容を記載したmy.cnf
ファイルをdockerディレクトリへ格納する。
[mysqld]
default-authentication-plugin = mysql_native_password
その後、docker-compose.ymlのvolumesにmy.cnfファイルを指定する。
services:
db:
image: mysql:8.0
+ volumes:
+ - ./my.cnf:/etc/mysql/my.cnf
3-3. バージョンアップ処理
マイグレーションまで問題なく実行される。
default-authentication-plugin
が変更されていることも確認
MySQL8.0
4. テストの実行
テスト成功
5. MySQLの文字コードを確認
テストは成功したが、バージョンアップの注意点にもあった文字コードを確認する。
SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
FROM information_schema.SCHEMATA
WHERE SCHEMA_NAME = 'データベース名';
DEFAULT_CHARACTER_SET_NAMEとDEFAULT_COLLATION_NAMEが変更されてしまっている。
これが変更されることにより、新規テーブル、新規カラム作成時にこちらの文字コードがデフォルトへ設定されてしまう。
しかし、Laravelの[config/database.php]に文字コードを設定していた場合、以降の対応は不要
<?php
return [
'connections' => [
'mysql' => [
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
],
],
];
※マイグレーションから操作する場合は問題ないが、MySQLを直接操作して、新規テーブル、新規カラム作成する場合、バージョンアップ前に以降の設定が必要
5-1. my.cnfを追加とdocker-compose.ymlの修正
下記の内容を記載したmy.cnf
ファイルをdockerディレクトリへ格納する。
# 既存のLaravelと同じにしたい場合
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
# MySQL5.7と同じ設定にしたい場合
[mysqld]
character-set-server = latin1
collation-server = latin1_swedish_ci
その後、docker-compose.yml
のvolumesにコピー先を指定する。
services:
db:
image: mysql:8.0
volumes:
- ./my.cnf:/etc/mysql/my.cnf
5-2. アップグレード処理
テストまで終了し、文字コードを確認する
SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
FROM information_schema.SCHEMATA
WHERE SCHEMA_NAME = 'データベース名';
MySQL8.0(対応後、既存のLaravelと同じにしたい場合)
MySQL8.0(対応後、MySQL5.7と同じ設定にしたい場合)
参考サイト