はじめに (対象読者・この記事でわかること)
このブログは、Web アプリケーション開発に携わるエンジニアを対象としています。特に、Node.js や PHP などのサーバーサイドから MySQL に格納された日本語テキストを取得し、ブラウザ上で正しく表示したい方に最適です。この記事を読むと、MySQL の文字セットや照合順序の設定ミス、クライアント側の接続文字コード、HTML の meta タグの指定ミスといった文字化けの典型的な原因を把握でき、実際の環境で即座に修正できる手順が身につきます。バックエンドとフロントエンドの両方の観点から根本的な対策を解説するので、同様の問題に直面した際のトラブルシューティングが格段に楽になります。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。
- MySQL の基本的な操作とスキーマ定義
- Node.js(特に
mysql2/mysqlパッケージ)でのデータベース接続 - HTML と CSS の基礎、特に
meta charsetの意味
MySQLと日本語文字列の基本
MySQL では文字列を格納する際に 文字セット (character set) と 照合順序 (collation) を設定します。日本語を扱う場合、主に次の 3 つが選択肢です。
| 文字セット | 主な用途 | 推奨理由 |
|---|---|---|
utf8 |
3 バイト UTF-8(MySQL 5.5 以前のデフォルト) | 互換性は高いが、一部の絵文字が格納できない |
utf8mb4 |
4 バイト UTF-8(完全な Unicode) | 絵文字や拡張漢字も安全に格納でき、現在の推奨設定 |
latin1 |
西欧文字だけ | 日本語には不適切 |
日本語テーブルが utf8mb4 で作成されていないと、データ投入時に 文字化け(??? や  など)が発生します。また、テーブルだけでなく データベース全体、カラム単位、接続時の文字コード すべてが整合していなければ、取得した文字列は正しくデコードできません。
さらに、MySQL の サーバー側変数 (character_set_server, collation_server) と クライアント側変数 (character_set_client, character_set_results, character_set_connection) が不一致になるケースが多く、これが「取得はできても表示が崩れる」という典型的な症状の根源です。したがって、データベース設計段階で統一した文字セットを選択し、接続時にも同じ文字セットを明示的に指定することが必須です。
日本語文字化けの原因と解決手順
以下では、実際に Node.js + MySQL 環境で日本語が文字化けしたケースを例に、原因究明から解決までの具体的な手順を解説します。総文字数は約 1500 字程度ですので、段階ごとに区切って読み進めてください。
ステップ1:データベース・テーブル・カラムの文字セット確認
まずは MySQL にログインし、対象データベース・テーブル・カラムの設定を確認します。
Sql-- データベースの文字セットと照合順序 SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = 'your_database'; -- テーブルの文字セットと照合順序 SHOW CREATE TABLE your_table\G -- カラム単位の確認 SELECT COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'your_database' AND TABLE_NAME = 'your_table';
ポイント
- utf8mb4 が設定されていない場合は、次のコマンドで変更します。
sql
ALTER DATABASE your_database CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
ALTER TABLE your_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
- すでにデータが latin1 で格納されている場合は、バイト列の再エンコード が必要です。具体的には、文字化けしたデータを CONVERT(BINARY column USING utf8mb4) で変換します。
ステップ2:接続時の文字セットを明示的に指定
Node.js の MySQL クライアントがデフォルトで utf8(3 バイト)を使用することがあります。そのため、utf8mb4 に合わせて接続設定を行います。
Jsconst mysql = require('mysql2'); const pool = mysql.createPool({ host: 'localhost', user: 'db_user', password: 'password', database: 'your_database', // ここで文字セットを明示 charset: 'utf8mb4', // 文字列を自動的に UTF-8 に変換 // 追加で以下のオプションを付与すると安全 // supportBigNumbers: true, // bigNumberStrings: true, }); module.exports = pool.promise();
ポイント
- charset: 'utf8mb4' を忘れがちですが、これが最も頻出する文字化けの原因です。
- 接続プールを使用する場合でも、pool.on('connection', ...) で SET NAMES utf8mb4; を明示的に送ることが有効です。
Jspool.on('connection', (connection) => { connection.query('SET NAMES utf8mb4;'); });
ステップ3:SQL 文の実行結果を正しく取得
取得した文字列は バッファ ではなく JavaScript の文字列 として扱われます。Node.js は内部的に UTF-8 として扱うため、先ほどの設定が正しければそのまま res.json() やテンプレートエンジンに渡すだけで OK です。ただし、console.log で確認するときにターミナルの文字コードが合っていない と再び文字化けして見えることがあります。ターミナル側も UTF-8 であることを確認してください。
ステップ4:HTML 側での文字コード宣言
ブラウザは HTML の <meta charset="UTF-8"> が最優先です。サーバーが Content-Type: text/html; charset=utf-8 を返していても、HTML 内に明示的に書かれていないと、古いブラウザは推測で別の文字コードを使用することがあります。
Html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>日本語表示テスト</title> </head> <body> <h1>データベースから取得した日本語</h1> <p id="msg"></p> <script> fetch('/api/message') .then(r => r.json()) .then(data => { document.getElementById('msg').textContent = data.message; }); </script> </body> </html>
ハマった点やエラー解決
| 発生した症状 | 原因 | 解決策 |
|---|---|---|
§§§ のような記号が表示される |
utf8mb4 未使用で絵文字が格納できていない |
データベース・テーブルを utf8mb4 に変更 |
API の JSON が \u3053\u3093... になる |
JSON.stringify がデフォルトでエスケープ |
res.json() を使用し、クライアント側でデコード |
開発環境のターミナルで ??? が出る |
ターミナルのロケールが C か POSIX |
export LANG=ja_JP.UTF-8 など環境変数を設定 |
SET NAMES utf8mb4 を入れ忘れた |
接続文字セットが latin1 のまま |
接続設定 charset: 'utf8mb4' を追記、再起動 |
解決策の総まとめ
- データベース・テーブル・カラム を
utf8mb4に統一。 - 接続時に
charset: 'utf8mb4'とSET NAMES utf8mb4;を必ず実行。 - HTML に
<meta charset="UTF-8">を必ず記載。 - ターミナル・IDE のロケールも UTF-8 に設定して、デバッグ時の表示ミスを防止。
これらを順番にチェックすれば、MySQL から取得した日本語が ブラウザ上で正しく表示され、文字化けが解消 されます。
まとめ
本記事では、MySQL に格納された日本語がクライアント側で文字化けする典型的な原因と、その 4 つの対策(データベース文字セット統一、接続文字セット指定、HTML の meta 宣言、環境ロケール設定)を詳しく解説しました。
- データベース全体を
utf8mb4に統一 すれば、絵文字や拡張漢字も安全に扱える。 - 接続時に
SET NAMES utf8mb4;を忘れないことで、取得データが正しくデコードされる。 - HTML の
<meta charset="UTF-8">がブラウザの文字コード選択を保証する。 - ローカル環境の文字コード設定 も合わせて見直すと、デバッグ時の混乱が防げる。
これらを踏まえて実装すれば、文字化けに悩まされることなく、安定した日本語表示が実現できます。次回は、多言語対応(i18n) に向けた文字セット設計や、ORM(Sequelize, TypeORM) での文字エンコーディング管理についても解説予定です。
参考資料
- MySQL 公式マニュアル – Unicode と文字セット
- Node.js mysql2 パッケージのドキュメント
- MDN – HTML の文字エンコーディング
- 『実践 MySQL 8.0 ― データベース設計と運用のすべて』 (技術評論社)
